134

我有一个层次结构Menu中的每个MenuItem都将其Command属性设置为RoutedCommand我定义的位置。关联提供了一个回调,用于控制每个 的启用状态CommandBinding的评估。CanExecuteMenuItem

几乎可以工作。菜单项最初带有正确的启用和禁用状态。但是,当我的CanExecute回调使用的数据发生变化时,我需要该命令从我的回调中重新请求结果,以使这个新状态反映在 UI 中。

对此似乎没有任何公共RoutedCommand方法CommandBinding

请注意,当我单击或键入控件时再次使用回调(我猜它是在输入时触发的,因为鼠标悬停不会导致刷新)。

4

6 回答 6

179

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

CommandManager.InvalidateRequerySuggested();

在MSDN上查看更多信息

于 2009-08-27T11:05:19.297 回答
85

对于以后遇到此问题的任何人;如果您碰巧正在使用 MVVM 和 Prism,那么 Prism 的DelegateCommand实现ICommand提供了一种.RaiseCanExecuteChanged()方法来执行此操作。

于 2011-06-17T16:49:45.803 回答
30

我无法使用CommandManager.InvalidateRequerySuggested();,因为我的性能受到了打击。

我使用了MVVM Helper的 Delegating 命令,如下所示(我为我们的 req 做了一些调整)。你必须command.RaiseCanExecuteChanged()从 VM打电话

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);
}
于 2011-12-12T13:30:07.827 回答
19

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

解决方案是使用以下内容:

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

    public void RaiseCanExecuteChanged()
    {
        CommandManager.InvalidateRequerySuggested();
    }

这样,订阅者将附加到CommandManager而不是您的班级,并且可以正确参与命令状态更改。

于 2017-02-08T10:05:27.067 回答
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 }
 );
于 2015-05-22T10:37:52.690 回答
-3

这对我有用:将 CanExecute 放在 XAML 中的命令之前。

于 2019-03-11T16:55:59.127 回答