每当有 UI 交互时,如何防止 CommandManager 调用 CanExecute?

How to prevent CommandManager from invoking CanExecute whenever there is UI interaction?

我们的 UI 目前有很多控件绑定到一些复杂的命令 CanExecutes。我们面临的问题是,每当 CommandManager 确定 UI 需要重新评估时,所有命令 运行 他们的 CanExecute,这反过来会导致相当大的性能针对特定场景命中。

阅读此 post:How does CommandManager.RequerySuggested work?

似乎 CommandManager 会在简单的按键按下、鼠标移动事件等时重新评估。有没有办法防止这种情况发生,而是让命令管理器在什么时候重新评估手动调用?

一个解决方案可能是实现一个更简单的 RelayCommand class 版本,它只存储事件处理程序本身并公开一个 public 方法以在适当的时候触发它们:

public class RelayCommand : ICommand
{
    public event EventHandler CanExecuteChanged;

    // Further ICommand implementation omitted...

    public void Invalidate()
    {
        var handler = this.CanExecuteChanged;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

然后您在 viewModel 中调用以下命令重新评估命令:

fooCommand.Invalidate();

当然,这会给您带来相反的问题,您现在必须手动重新评估所有命令...

编辑

要详细说明评论,大多数 RelayCommand 会像这样实施 CanExecuteChanged 事件:

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

当 UI 订阅命令的 CanExecuteChanged 事件时,它实际上是间接订阅了 CommandManager.RequerySuggested 事件,这就是为什么您的 CanExecute 方法每次都被调用的原因CommandManager 建议重新查询的时间。

我建议的更简单的 RelayCommand 通过不订阅 CommandManager.RequerySuggested 事件来避免这个问题。