【问题标题】:How to prevent CommandManager from invoking CanExecute whenever there is UI interaction?每当有 UI 交互时,如何防止 CommandManager 调用 CanExecute?
【发布时间】:2015-01-12 22:36:05
【问题描述】:

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

阅读这篇文章:How does CommandManager.RequerySuggested work?

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

【问题讨论】:

  • 我不认为你可以。 CanExecute 不应包含任何复杂的功能。也许您可以创建一个 bool 变量来告诉您它是否可以执行,并在条件发生变化时更改此变量?
  • 你什么时候/在哪里调用它?
  • @Dzyann,一个好的场景是当一个特定事件完成运行(或被引发),然后让所有命令“重新评估”
  • 我会保留所有内容,并在导致问题的特定位置添加额外的验证。考虑到将来更改 CommandManager 的默认行为可能会导致各种问题。一个不知情的程序员在某些地方添加逻辑并且永远不会被解雇。我想只有代码的某些部分会导致性能问题。

标签: c# wpf xaml relaycommand


【解决方案1】:

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

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();

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

编辑

为了详细说明 cmets,大多数RelayCommand 都像这样实现CanExecuteChanged 事件:

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

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

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

【讨论】:

  • Ben,我可以看到这将如何提供手动调用机制,但我不明白这如何阻止 CommandManager 基于 UI 交互自动调用。
  • 它不会停止CommandManager 但没关系。简化的 RelayCommand 不会将任何已注册的事件处理程序传递给 CommandManager,这意味着 UI 不会在每次触发 RequerySuggested 事件时重新评估命令。
  • Ben,这为我的问题提供了一种机制。谢谢!
猜你喜欢
  • 2013-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-12
  • 1970-01-01
  • 2012-12-27
  • 2019-08-21
  • 2020-04-11
相关资源
最近更新 更多