【问题标题】:RelayCommand RaiseCanExecuteChanged() failsRelayCommand RaiseCanExecuteChanged() 失败
【发布时间】:2011-10-19 11:48:06
【问题描述】:

我正在使用几个绑定到 RelayCommands 的按钮,这些 RelayCommands 由 CanExecute 委托初始化。

RelayCommand DeleteCommand;
bool CanDelete()
{
    return BoolProp1 && BoolProp2;
}

...

DeleteCommand = new RelayCommand(Delete, CanDelete);

BoolProp1BoolProp2 是常规属性,setter 正确地提升了PropertyChanged,但众所周知,这不足以让 SL 在命令上重新评估 CanExecute。这就是为什么我在两个 setter 中都调用 Delete.RaiseCanExecuteChanged()

直到某个时候,所有这些都可以正常工作(按钮被禁用和启用),所有这些都停止了。那时,调用Delete.RaiseCanExecuteChanged() 不再触发我在CanDelete() 中的断点,并且按钮将永远保持原样。

我花了 2 个小时试图找出确切的原因,但没有任何效果。我怀疑在单个“绑定迭代”期间多次调用 RaiseCanExecuteChanged() 会以某种方式破坏机制。

有什么提示吗?我已经在考虑使用通过INotifyPropertyChanged 刷新的额外IsExecutable 字段...

更新

RelayCommand 实际上是来自MVVM Light ToolkitGalaSoft.MvvmLight.Command.RelayCommand。 ILSpy 展示了一个非常简单的 ICommand 实现:

public bool CanExecute(object parameter)
{
    return this._canExecute == null || this._canExecute.Invoke();
}

public void RaiseCanExecuteChanged()
{
    EventHandler canExecuteChanged = this.CanExecuteChanged;
    if (canExecuteChanged != null)
    {
         canExecuteChanged.Invoke(this, EventArgs.Empty);
    }
}

_canExecuteFunc<bool> 设置一次为传递给构造函数的值。

我仍在努力尽量减少重现该问题。

更新

看我的回答。

【问题讨论】:

  • 发布更多代码。什么是 RelayCommandEx?命令实现是什么样的?如果可能,创建一个非常简单的复制并发布完整的代码。
  • RelayCommandEx 是我处理此问题的失败尝试(尝试缓存 CanExecute() 值,如果不需要则不触发 CanExecuteChanged)。
  • 我有一个模糊的记忆,它与某些事情有关(我认为在我的情况下它是 WPF 按钮)没有缓存 EventHandler 和弱引用。当我有时间时会尝试弄清楚它是什么,但可能会帮助你走上正确的道路。您可能希望为 CanExecuteChanged 事件实现添加/删除访问器,然后在 remove 中设置断点以查看它何时被删除。
  • 看我的回答。谢谢你的时间。

标签: c# silverlight mvvm mvvm-light relaycommand


【解决方案1】:

PEBKAC。我的框架在某些情况下会运行代码

DeleteCommand = new RelayCommand(Delete, CanDelete);

不止一次,用新实例覆盖实际绑定到视图的命令。

如果有人遇到此问题 - 请确保您在视图绑定到的同一实例上调用 RelayCommand.RaiseCanExecuteChanged()

【讨论】:

    【解决方案2】:

    对于遇到同样问题且接受的答案对我没有帮助的其他人(为了我自己的记录,因为我今天花了几个小时来处理它)。

    如果您在 VSTO 加载项中使用 MVVM Light,请确保 Office 应用程序有机会处理自己的消息以使其正常工作。例如,在我的情况下,我的 Ribbon 按钮监听了底层 VM 的命令对象的 CanExecuteChanged,无论我做什么都不会触发。花了几个小时后,我意识到我必须让 Office 应用程序喘口气并处理传入的消息,以允许 CanExecuteChanged 被加载项捕获。然后我所做的就是将我的RaiseCanExecuteChanged 函数交给DispatcherHelper 让它异步触发。直到那时我的功能区按钮才开始对CanExecuteChanged 事件做出反应。像这样的:

    DispatcherHelper.CheckBeginInvokeOnUI(() =>
    {
      doc.Activate();
      ResetVariablesCommand.RaiseCanExecuteChanged();
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-21
      • 2012-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多