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

发布于 2024-08-02 14:44:09 字数 477 浏览 4 评论 0 原文

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

几乎有效。菜单项最初会显示正确的启用和禁用状态。但是,当我的 CanExecute 回调使用的数据发生更改时,我需要命令从回调中重新请求结果,以便在 UI 中反映此新状态。

RoatedCommandCommandBinding 上似乎没有任何公共方法可以实现此目的。

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

I have a Menu where each MenuItem in the hierarchy has its Command property set to a RoutedCommand I've defined. The associated CommandBinding provides a callback for the evaluation of CanExecute which controls the enabled state of each MenuItem.

This almost works. The menu items initially come up with the correct enabled and disabled states. However when the data that my CanExecute callback uses changes, I need the command to re-request a result from my callback in order for this new state to be reflected in the UI.

There do not appear to be any public methods on RoutedCommand or CommandBinding for this.

Note that the callback is used again when I click or type into the control (I guess it's triggered on input because mouse-over doesn't cause the refresh).

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

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

发布评论

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

评论(6

别挽留 2024-08-09 14:44:09

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

CommandManager.InvalidateRequerySuggested();

请参阅 MSDN

Not the prettiest in the book, but you can use the CommandManager to invalidate all commandbinding:

CommandManager.InvalidateRequerySuggested();

See more info on MSDN

征﹌骨岁月お 2024-08-09 14:44:09

对于后来遇到这个问题的人;如果您碰巧使用 MVVM 和 Prism,那么 Prism 的 ICommandDelegateCommand 实现提供了一个 .RaiseCanExecuteChanged() 方法来执行此操作。

For anyone who comes across this later; If you happen to be using MVVM and Prism, then Prism's DelegateCommand implementation of ICommand provides a .RaiseCanExecuteChanged() method to do this.

dawn曙光 2024-08-09 14:44:09

我无法使用 CommandManager.InvalidateRequerySuggested(); 因为我的性能受到了影响。

我使用了 MVVM Helper 的委托命令,如下所示(我根据我们的要求对其进行了一些调整)。你必须从VM调用command.RaiseCanExecuteChanged()

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

I couldnt use CommandManager.InvalidateRequerySuggested(); because I was getting performance hit.

I have used MVVM Helper's Delegating command, which looks like below (i have tweaked it a bit for our req). you have to call command.RaiseCanExecuteChanged() from 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);
}
甜心小果奶 2024-08-09 14:44:09

如果您已经推出了自己的实现 ICommand 的类,您可能会丢失大量自动状态更新,迫使您依赖于手动刷新而不是需要的。它还可能破坏 InvalidateRequerySuggested()。问题在于简单的 ICommand 实现无法将新命令链接到 CommandManager

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

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

    public void RaiseCanExecuteChanged()
    {
        CommandManager.InvalidateRequerySuggested();
    }

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

If you have rolled your own class that implements ICommand you can lose a lot of the automatic status updates forcing you to rely on manual refreshing more than should be needed. It can also break InvalidateRequerySuggested(). The problem is that a simple ICommand implementation fails to link the new command to the CommandManager.

The solution is to use the following:

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

    public void RaiseCanExecuteChanged()
    {
        CommandManager.InvalidateRequerySuggested();
    }

This way subscribers attach to CommandManager rather than your class and can properly participate in command status changes.

胡大本事 2024-08-09 14:44:09

我已经实现了一个解决方案来处理命令的属性依赖性,此处链接 https://stackoverflow.com/a/30394333/1716620< /a>

感谢您最终会得到这样的命令:

this.SaveCommand = new MyDelegateCommand<MyViewModel>(this,
    //execute
    () => {
      Console.Write("EXECUTED");
    },
    //can execute
    () => {
      Console.Write("Checking Validity");
       return PropertyX!=null && PropertyY!=null && PropertyY.Length < 5;
    },
    //properties to watch
    (p) => new { p.PropertyX, p.PropertyY }
 );

I've implemented a solution to handle property dependency on commands, here the link https://stackoverflow.com/a/30394333/1716620

thanks to that you'll end up having a command like this:

this.SaveCommand = new MyDelegateCommand<MyViewModel>(this,
    //execute
    () => {
      Console.Write("EXECUTED");
    },
    //can execute
    () => {
      Console.Write("Checking Validity");
       return PropertyX!=null && PropertyY!=null && PropertyY.Length < 5;
    },
    //properties to watch
    (p) => new { p.PropertyX, p.PropertyY }
 );
纵山崖 2024-08-09 14:44:09

这对我有用:将 CanExecute 放在 XAML 中的 Command 之前。

This is what worked for me: Put the CanExecute before the Command in the XAML.

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