CanExecuteChanged 和 CommandManager.RequerySuggested 的实际任务是什么?

发布于 2024-11-19 08:41:33 字数 580 浏览 1 评论 0原文

我从 Josh Smith 的 MVVM 教程 中获得了以下代码。

谁能快速解释一下这段代码的实际用途?

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

我不明白两件事:

  1. CanExecuteChanged 事件是做什么的?
  2. CommandManager.RequerySuggested 的作用是什么?

上面的代码来自此处RelayCommand类。

I got the following code from Josh Smith's MVVM tutorial.

Can anyone provide a quick explanation of what this code actually does?

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

I can't understand two things:

  1. what does the CanExecuteChanged event do?
  2. what does the CommandManager.RequerySuggested do?

The above code is from the RelayCommand Class from here.

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

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

发布评论

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

评论(3

你是年少的欢喜 2024-11-26 08:41:33
  1. CanExecuteChanged 通知绑定到该 ICommand 的任何命令源(如 ButtonMenuItem)返回的值由 CanExecute 已更改。命令源关心这一点,因为它们通常需要相应地更新其状态(例如,如果 CanExecute() 返回 false,则 Button 将禁用自身) 。
  2. 每当 CommandManager 认为某些内容发生变化会影响命令执行能力时,就会引发 CommandManager.RequerySuggested 事件。例如,这可能是焦点的改变。事实证明这个事件火了很多。

因此,本质上,这段代码的作用是确保每当命令管理器认为命令的执行能力发生更改时,该命令都会引发 CanExecuteChanged 即使它实际上没有更改。

我实际上不喜欢这种实现 ICommand.CanExecuteChanged 的​​方法 - 它感觉很懒而且不完全可靠。我更喜欢更细粒度的方法,其中命令公开一个方法(例如 RaiseCanExecuteChanged()),您可以调用它来引发 CanExecuteChanged,然后在适当的位置调用它来自您的视图模型的时间。

例如,如果您有一个删除当前选定客户的命令,则它会有一个 CanExecute() 处理程序,仅当选择了一个客户时才返回 true。因此,只要选定的客户发生变化,您就可以调用 RaiseCanExecuteChanged

  1. CanExecuteChanged notifies any command sources (like a Button or MenuItem) that are bound to that ICommand that the value returned by CanExecute has changed. Command sources care about this because they generally need to update their status accordingly (eg. a Button will disable itself if CanExecute() returns false).
  2. The CommandManager.RequerySuggested event is raised whenever the CommandManager thinks that something has changed that will affect the ability of commands to execute. This might be a change of focus, for example. Turns out that this event fires a lot.

So, in essence, what this bit of code does is ensure that whenever the command manager thinks a command's ability to execute has changed, the command will raise CanExecuteChanged even if it hasn't actually changed.

I actually dislike this approach to implementing ICommand.CanExecuteChanged - it feels lazy and isn't entirely reliable. I prefer a much more fine-grained approach where the command exposes a method (eg. RaiseCanExecuteChanged()) you can call to raise CanExecuteChanged, then you call this at the appropriate times from your view model.

For example, if you have a command that deletes the currently selected customer, it would have a CanExecute() handler that returns true only if there is a customer selected. You would therefore call RaiseCanExecuteChanged whenever the selected customer changes.

以为你会在 2024-11-26 08:41:33
  • RoatedCommands 可以自动通知它们的 CanExecute 是否已更改,因为我们在这里实现 ICommand,WPF 系统不知道这一点,我们将其连线将它们发送给 CommandManager 的 RequerySuggested 事件。
  • 现在,当焦点发生变化、编辑任何控件等时,WPF 系统会经常调用此事件。因此会引发 CanExecuteChanged。当您的按钮正在侦听此事件时,它将重新调用 CanExecute 以了解最新状态。

这是一篇您可能感兴趣的文章

  • RoutedCommands can automatically notify if their CanExecute has changed, since we are implementing ICommand here, which the WPF system doesn't know about, we wire them to CommandManager's RequerySuggested event.
  • Now this event is called quite often by the WPF system when the focus changes, any control is edited etc. Hence in turn CanExecuteChanged is raised. As your button is listening to this event it will reinvoke CanExecute to know the latest status.

Here is an article that might be of interest.

等待圉鍢 2024-11-26 08:41:33

实现 RaiseCanExecuteChanged()

命令类:

public class CommandBase : ICommand
{
    Action _TargetExecuteMethod;
    Func<bool> _TargetCanExecuteMethod;

    public CommandBase(Action executeMethod)
    {
        _TargetExecuteMethod = executeMethod;
    }

    public CommandBase(Action executeMethod, Func<bool> canExecuteMethod)
    {
        _TargetExecuteMethod = executeMethod;
        _TargetCanExecuteMethod = canExecuteMethod;
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    public event EventHandler CanExecuteChanged

    public bool CanExecute(object parameter)
    {             

        if (_TargetCanExecuteMethod != null)
        {
            return _TargetCanExecuteMethod();
        }

        if (_TargetExecuteMethod != null)
        {
            return true;
        }                       
                    
        return false;
    }

    public void Execute(object parameter)
    {
        if (_TargetExecuteMethod != null)
        {
            _TargetExecuteMethod();
        }
    }
}

View:

<TextBox Grid.Row="3" Text="{Binding TextValue, UpdateSourceTrigger=PropertyChanged }"/>
<Button Content="DoSomething" Command="{Binding DoSomething}" />

ViewModel 类:

public class MyclassViewModel
{
     private string textValue;

     public String TextValue
     {
        get {                
            return textValue; 
        }
        set {               
            textValue = value;
            DoSomething.RaiseCanExecuteChanged();
        }
     }

     public CommandBase DoSomething { get; set; }

     public MyclassViewModel() //Constructor
     {            
        DoSomething = new CommandBase(OnDoSomething, CanDoSomething);            
     }

     private bool CanDoSomething()
     {
        if (TextValue?.Length > 5)
        {
            return true;
        }
        return false;
     }

    private void OnDoSomething()
    {
        //Do Something
    }
}

Implementing RaiseCanExecuteChanged()

Command Class:

public class CommandBase : ICommand
{
    Action _TargetExecuteMethod;
    Func<bool> _TargetCanExecuteMethod;

    public CommandBase(Action executeMethod)
    {
        _TargetExecuteMethod = executeMethod;
    }

    public CommandBase(Action executeMethod, Func<bool> canExecuteMethod)
    {
        _TargetExecuteMethod = executeMethod;
        _TargetCanExecuteMethod = canExecuteMethod;
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    public event EventHandler CanExecuteChanged

    public bool CanExecute(object parameter)
    {             

        if (_TargetCanExecuteMethod != null)
        {
            return _TargetCanExecuteMethod();
        }

        if (_TargetExecuteMethod != null)
        {
            return true;
        }                       
                    
        return false;
    }

    public void Execute(object parameter)
    {
        if (_TargetExecuteMethod != null)
        {
            _TargetExecuteMethod();
        }
    }
}

View:

<TextBox Grid.Row="3" Text="{Binding TextValue, UpdateSourceTrigger=PropertyChanged }"/>
<Button Content="DoSomething" Command="{Binding DoSomething}" />

ViewModel class:

public class MyclassViewModel
{
     private string textValue;

     public String TextValue
     {
        get {                
            return textValue; 
        }
        set {               
            textValue = value;
            DoSomething.RaiseCanExecuteChanged();
        }
     }

     public CommandBase DoSomething { get; set; }

     public MyclassViewModel() //Constructor
     {            
        DoSomething = new CommandBase(OnDoSomething, CanDoSomething);            
     }

     private bool CanDoSomething()
     {
        if (TextValue?.Length > 5)
        {
            return true;
        }
        return false;
     }

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