我有一个Menu
,其中层次结构中的每个MenuItem
都将其Command
属性设置为我定义的RoutedCommand
。关联的CommandBinding
为评估CanExecute
提供了一个回调,用于控制每个MenuItem
的启用状态。
这几乎有效。菜单项最初会显示正确的启用和禁用状态。但是,当我的CanExecute
回调使用的数据发生变化时,我需要命令从我的回调中重新请求结果,以便在UI中反映这种新状态。
RoutedCommand
或CommandBinding
似乎没有任何公开方法。
请注意,当我单击或输入控件时,会再次使用回调(我猜它是在输入时触发的,因为鼠标悬停不会导致刷新)。
答案 0 :(得分:163)
本书中不是最漂亮的,但您可以使用CommandManager使所有命令绑定无效:
CommandManager.InvalidateRequerySuggested();
查看有关MSDN
的更多信息答案 1 :(得分:79)
对于后来遇到此事的人;如果你碰巧使用的是MVVM和Prism,那么Prism的DelegateCommand
ICommand
实现提供了.RaiseCanExecuteChanged()
方法来实现这一点。
答案 2 :(得分:23)
我无法使用CommandManager.InvalidateRequerySuggested();
因为我的性能受到了影响。
我使用了MVVM Helper的委派命令,如下所示(我已经为我们的req稍微调整了一下)。你必须从VM调用command.RaiseCanExecuteChanged()
public event EventHandler CanExecuteChanged
{
add
{
_internalCanExecuteChanged += value;
CommandManager.RequerySuggested += value;
}
remove
{
_internalCanExecuteChanged -= value;
CommandManager.RequerySuggested -= value;
}
}
/// <summary>
/// This method can be used to raise the CanExecuteChanged handler.
/// This will force WPF to re-query the status of this command directly.
/// </summary>
public void RaiseCanExecuteChanged()
{
if (canExecute != null)
OnCanExecuteChanged();
}
/// <summary>
/// This method is used to walk the delegate chain and well WPF that
/// our command execution status has changed.
/// </summary>
protected virtual void OnCanExecuteChanged()
{
EventHandler eCanExecuteChanged = _internalCanExecuteChanged;
if (eCanExecuteChanged != null)
eCanExecuteChanged(this, EventArgs.Empty);
}
答案 3 :(得分:13)
如果你已经推出了自己的实现ICommand
的类,那么你可能会失去很多自动状态更新,迫使你依赖手动刷新而不是需要。它也可以打破InvalidateRequerySuggested()
。问题是简单的ICommand
实现无法将新命令链接到CommandManager
。
解决方案是使用以下内容:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
这样订阅者就可以附加到CommandManager
而非您的班级,并且可以正确参与命令状态更改。
答案 4 :(得分:2)
我已经实现了一个处理命令属性依赖的解决方案,这里是链接https://stackoverflow.com/a/30394333/1716620
多亏了你最终会得到这样的命令:
this.SaveCommand = new MyDelegateCommand<MyViewModel>(this,
//execute
() => {
Console.Write("EXECUTED");
},
//can execute
() => {
Console.Write("Checking Validity");
return PropertyX!=null && PropertyY!=null && PropertyY.Length < 5;
},
//properties to watch
(p) => new { p.PropertyX, p.PropertyY }
);
答案 5 :(得分:0)
这对我有用:将CanExecute放在XAML中的命令之前。