WPF - 如何强制命令通过其CommandBindings重新评估'CanExecute'

Dre*_*kes 125 .net wpf command commandbinding

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

几乎可行.菜单项最初会显示正确的启用和禁用状态.但是,当我的CanExecute回调使用的数据发生变化时,我需要命令从我的回调中重新请求结果,以便在UI中反映这种新状态.

似乎没有任何公共方法RoutedCommandCommandBinding为此.

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

Arc*_*rus 166

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

CommandManager.InvalidateRequerySuggested();
Run Code Online (Sandbox Code Playgroud)

MSDN上查看更多信息

  • 请注意其他答案(http://stackoverflow.com/questions/783104/refresh-wpf-command)"必须在UI线程上调用它" (8认同)
  • 我编辑了你的答案,以便重新申请我的投票.我在编辑中没有改变任何东西.再次感谢. (4认同)

Cod*_*ike 83

对于后来遇到此事的人; 如果您碰巧使用MVVM和Prism,那么Prism的DelegateCommand实现ICommand提供了一种.RaiseCanExecuteChanged()方法来实现这一点.

  • 此模式也可以在其他MVVM库中找到,例如MVVM Light. (12认同)
  • 在WPF MVVM Light的旁注中,你需要使用命名空间GalaSoft.MvvmLight.CommandWpf,因为GalaSoft.MvvmLight.Command会引起麻烦http://www.mvvmlight.net/installing/changes#v5_0_2 (4认同)
  • 与Prism不同,MVVM Light v5的源代码指示其`RaiseCanExecuteChanged()`只是调用`CommandManager.InvalidateRequerySuggested()`。 (2认同)

Bek*_*pov 26

我无法使用,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);
}
Run Code Online (Sandbox Code Playgroud)

  • 只是一个FYI我注释掉了CommandManager.RequerySuggested + = value; 出于某种原因,我正在对CanExecute代码进行近乎恒定/循环的评估.否则解决方案按预期工作.谢谢! (2认同)

小智 14

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

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

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

    public void RaiseCanExecuteChanged()
    {
        CommandManager.InvalidateRequerySuggested();
    }
Run Code Online (Sandbox Code Playgroud)

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

  • 直截了当,并且允许人们控制他们的ICommand实现. (2认同)