RelayCommand RaiseCanExecuteChanged() 失败

发布于 2024-11-27 22:17:46 字数 1512 浏览 4 评论 0 原文

我正在使用几个绑定到使用 CanExecute 委托初始化的 RelayCommand 的按钮。

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

...

DeleteCommand = new RelayCommand(Delete, CanDelete);

BoolProp1BoolProp2 是常规属性,setter 会正确引发 PropertyChanged,但众所周知,这不足以使 SL 重新评估 可以执行命令。这就是为什么我还在两个 setter 中调用 Delete.RaiseCanExecuteChanged()

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

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

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

UPDATE

RelayCommand 实际上是 MVVM Light 工具包 的 >GalaSoft.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);
    }
}

_canExecute 是一个 Func,设置为传递给构造函数的值一次。

我仍在努力最小化地重现该问题。

更新

请参阅我的回答。

I am using a couple of Buttons bound to RelayCommands initialized with CanExecute delegates.

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

...

DeleteCommand = new RelayCommand(Delete, CanDelete);

BoolProp1 and BoolProp2 are regular properties with setters correctly raising PropertyChanged, but as we all know, this is not enough to make SL reevaluate CanExecute on commands. That's why i also call Delete.RaiseCanExecuteChanged() in both setters.

All this works fine (buttons are disabled and enabled properly) up to some point, where is all stops. At that point, calling Delete.RaiseCanExecuteChanged() no longer fires my breakpoints in CanDelete() and buttons forever stay the way they were.

I spend 2 hours trying to isolate the exact cause with no effect. I suspect multiple RaiseCanExecuteChanged() calls during single "binding iteration" somehow break the mechanism.

Any hints? I'm already considering using an additional IsExecutable field refreshed through INotifyPropertyChanged...

UPDATE

RelayCommand is actually GalaSoft.MvvmLight.Command.RelayCommand from MVVM Light Toolkit. ILSpy shows a pretty trivial implementation of 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);
    }
}

with _canExecute being a Func<bool> set once to the value passed to constructor.

I am still working to minimally reproduce the issue.

UPDATE

See my answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

南薇 2024-12-04 22:17:46

聚醚醚酮。 运行代码

DeleteCommand = new RelayCommand(Delete, CanDelete);

在某些情况下,我的框架多次

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

PEBKAC. My framework in certain cases ran the code

DeleteCommand = new RelayCommand(Delete, CanDelete);

more then once, overwriting commands that were actually bound to view with new instances.

If somebody has this problem - make sure you're calling RelayCommand.RaiseCanExecuteChanged() on the same instance that the view is bound to.

我的鱼塘能养鲲 2024-12-04 22:17:46

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

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

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

For anyone else who faced the same issue and the accepted answer didn't help me (and for my own record, as I spent a few hours today with it).

If you're using MVVM Light in a VSTO add-in, make sure that the Office application gets a chance to process its own messages to get this to work. For example, in my case I had my Ribbon buttons listening to CanExecuteChanged of underlying VM's command objects, which would not fire no matter what I did. After spending a few hours, I realized that I had to let Office application take a breath and process incoming message to allow CanExecuteChanged to be caught by the add-in. What I then did was to hand over my RaiseCanExecuteChanged function to DispatcherHelper to let it fire asynchronously. It was only then that my Ribbon buttons started reacting to CanExecuteChanged events. Something like this:

DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
  doc.Activate();
  ResetVariablesCommand.RaiseCanExecuteChanged();
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文