Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么人们在ICommands上使用CommandManager.InvalidateRequestSuggested()?_C#_Wpf - Fatal编程技术网

C# 为什么人们在ICommands上使用CommandManager.InvalidateRequestSuggested()?

C# 为什么人们在ICommands上使用CommandManager.InvalidateRequestSuggested()?,c#,wpf,C#,Wpf,我正在制作一些自己的自定义ICommand实现,我看到很多实现都是这样的: public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } protected void RaiseCanExecuteChanged() {

我正在制作一些自己的自定义ICommand实现,我看到很多实现都是这样的:

public event EventHandler CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
}

protected void RaiseCanExecuteChanged()
{        
    CommandManager.InvalidateRequerySuggested();
}
据我所知,这是一个优化效果很差的代码,因为调用
RaiseCanecuteChanged()
将触发UI中的所有命令来检查它们的
ICommand.CanExecute
状态,而通常我们只需要其中一个来验证它

我想我读过一次,这是一些WPF ICommand(如
RoutedCommand
)的主代码,对他们来说,这是有意义的,因为他们希望在某些控件失去焦点时自动重新验证所有ICommand,诸如此类,但我仍然不明白为什么人们在自己的
ICommand
实现中重复这种模式

我想到的代码是一个简单的事件调用,例如:

public event EventHandler CanExecuteChanged;

protected void RaiseCanExecuteChanged()
{        
    CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
我已经测试过了,这很有效,所以为什么web上的所有示例都没有实现这么简单的东西?我错过了什么吗?

我读过关于在常规事件中使用强引用的内存泄漏问题,
CommandManager
只使用
WeakReferences
,这在视图被垃圾收集的情况下是很好的,但是,没有任何解决方案不会影响内存占用的性能吗?

为什么web上的所有示例都没有实现像这样简单的东西?我错过什么了吗


我猜这主要是因为懒惰。。。你的建议确实是一个更好(更有效)的实现。但是,它还没有完成:您仍然需要订阅
CommandManager。RequerySuggestized
在命令上提升
CanExecuteChanged

非常简单-如果您在
ICommand.CanExecute()
中执行繁重的工作,那么您使用的
命令就非常糟糕。如果您遵循该规则,那么调用
CommandManager.invalidateRequestSuggested()
实际上不会对性能造成严重影响

实际上,它的实现比您建议的要简单得多


就我个人而言,我宁愿在一个特定的
ViewModel
中调用
CommandManager.invalidateRequestSuggested()
,当一个属性发生变化时,用户的反馈是即时的(即在表单完成/有效后立即启用按钮)。

这个问题很老了,现在是2019年,但我找到了使用CommandManager.InvalidateRequestSuggested()的另一个原因

我已经为WPF应用程序编写了自己的自定义ICommand类,在该类中,我首先直接调用CanExecuteChange,如下所示

public void RaiseCanExecuteChanged()
{
    CanExecuteChanged?.Invoke(this, null); 
}
我的WPF应用程序大量使用不同的线程,当从另一个线程然后从主UI线程调用上述方法时,它不会抛出错误,只是有点被忽略了。更糟糕的是,我发现调用方法中的所有代码行都被跳过了,这导致了奇怪的结果

我不知道确切的原因,但我想原因是,CanExecuteChange导致我的UI发生了变化,不能从另一个线程更改

但是,当我将ICommand更改为CommandManager.InvalidateRequestSuggested()时,就没有问题了。似乎可以从任何线程调用CommandManager.InvalidateRequestSuggested(),UI仍然会得到更新

public event EventHandler CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
}

public void RaiseCanExecuteChanged()
{
    CommandManager.InvalidateRequerySuggested();
}
我认为这可能是一个有价值的答案,因为在我找到这个解决方案之前,我对这个问题调试了3个小时。查找此问题的问题是,调试时没有抛出错误。代码被跳过了。非常奇怪的行为。

这就是答案。确实,
CanExecuteChanged?.Invoke(这个,null)必须由主UI线程调用

简单地写下如下:

public void RaiseCanExecuteChanged()
{
    Application.Current.Dispatcher.Invoke(() => CanExecuteChanged?.Invoke(this, null)); 
}
这就解决了您的问题,您可以只重新查询一个命令。然而,确实应该尽可能快地执行
CanExecute
-方法,因为它无论如何都会定期执行。
最好让CanExecute只包含一个
return foo
其中
foo
是一个可以在调用
CommandManager.invalidateRequestSuggested()之前设置的字段

为什么?我测试了这个,它是有效的。。。我缺少哪种情况场景?@mFeinstein,“它在您测试的情况下工作”,但调用
CommandManager.InvalidateRequestSuggested()
不会在您的命令上引发
CanExecuteChanged
。@mFeinstein,但它应该。这就是调用
CommandManager.invalidateRequestSuggested()
:以确保重新计算所有命令的
CanExecute()
。你是对的,命令本身不应该调用它,但是其他代码可以(并且确实)调用它。值得一提的是,这里是我的典型实现:@mFeinstein它其实并不重要,因为
RequerySuggested
只包含一个弱引用。很抱歉,我不理解你的观点,5行解决方案是什么“编程更简单“比三行解决方案更简单,因为您不必对受该属性影响的每个
命令
进行每次更改调用
RaiseCanceTechChanged
。从这个意义上说,它是,但我认为它在概念上有缺陷。RaiseCanExecuteChanged我相信是为了让ViewModel能够通知特定的命令,只有他,他的CanExecute状态发生了变化。CommandManager是通知所有人的人。我无法想象在任何编程情况下,为了激活一个对象而激活所有对象都被认为是良好的做法。这就像在街上大喊大叫,让每个人都开门,而不是按你想要的门铃。。。。但是,如果你让你的CanExecute保持简单并且几乎没有命令,我仍然理解它的简单性。尝试文字处理应用程序的文本/段落格式栏。如果您的文档和格式化命令主机完全分离