WPF – 如何强制命令通过其CommandBindings重新评估“CanExecute”

我有一个Menu ,其中层次结构中的每个MenuItemCommand属性设置为我定义的RoutedCommand 。 关联的CommandBinding为评估CanExecute提供了一个callback,它控制着每个MenuItem的启用状态。

几乎工作。 菜单项最初出现正确的启用和禁用状态。 但是,当我的CanExecutecallback使用更改的数据时,我需要命令重新请求我的callback结果,以便在UI中反映此新状态。

RoutedCommandCommandBinding上没有任何公开的方法。

请注意,当我单击或键入到控件(我猜这是由于input触发,因为鼠标hover不会导致刷新),callback被再次使用。

不是书中最漂亮的,但可以使用CommandManager来使所有的命令绑定失效:

 CommandManager.InvalidateRequerySuggested(); 

在MSDN上查看更多信息

对于后来碰到的人来说, 如果碰巧使用MVVM和Prism,那么Prism的ICommandDelegateCommand实现提供了一个.RaiseCanExecuteChanged()方法来执行此操作。

我无法使用CommandManager.InvalidateRequerySuggested(); 因为我受到了打击

我已经使用了MVVM Helper的Delegating命令,如下所示(我已经调整了一下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); } 

如果您已经推出了实现ICommand自己的类,则可能会失去很多自动状态更新,从而迫使您手动刷新超过应有的需求。 它也可以打破InvalidateRequerySuggested() 。 问题是一个简单的ICommand实现无法将新命令链接到CommandManager

解决scheme是使用以下内容:

  public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public void RaiseCanExecuteChanged() { CommandManager.InvalidateRequerySuggested(); } 

这样用户就可以连接到CommandManager而不是你的类,并且可以正确地参与命令状态的改变。

我已经实现了一个解决scheme来处理对命令的属性依赖,这里的链接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 } );