Why people use CommandManager.InvalidateRequerySuggested() on ICommands?

后端 未结 4 963
悲哀的现实
悲哀的现实 2021-02-20 17:23

I am making some custom ICommand implementation of my own and I see A LOT of implementations going like this:

public event EventHandler CanExecuteChanged
{
    a         


        
相关标签:
4条回答
  • 2021-02-20 17:31

    This is an answer to this answer. It is true that the CanExecuteChanged?.Invoke(this, null); has to be called by the main UI thread.

    Simply write it like follows:

    public void RaiseCanExecuteChanged()
    {
        Application.Current.Dispatcher.Invoke(() => CanExecuteChanged?.Invoke(this, null)); 
    }
    

    This solves your problem and you can requery just one command. It is however true that you should nevertheless make your CanExecute-Method as fast as possible, as it will anyways be periodically executed. It is best to have CanExecute just consist of a single return foo; where foo is a field you can set right before you call CommandManager.InvalidateRequerySuggested();.

    0 讨论(0)
  • 2021-02-20 17:40

    Why all the examples on the web don't implement something as simple as this? Am I missing something?

    I'm guessing it's mostly due to laziness... What you propose is indeed a better (more efficient) implementation. However, it's not complete: you still need to subscribe to CommandManager.RequerySuggested to raise CanExecuteChanged on the command.

    0 讨论(0)
  • 2021-02-20 17:43

    Very simply - if you are performing heavy work in ICommand.CanExecute() then you are using Commands very badly. If you follow that rule there should in fact be no serious performance implication to calling CommandManager.InvalidateRequerySuggested().

    Pragmatically, it's a much easier implementation than what you've suggested.

    Personally, I rather call CommandManager.InvalidateRequerySuggested() in a particular ViewModel when a property changes so that the feedback to the user is instantaneous (i.e. enabling a button as soon as a form is completed/valid).

    0 讨论(0)
  • 2021-02-20 17:50

    This question is quite old, it's 2019 now, but I have found another reason to use CommandManager.InvalidateRequerySuggested().

    I have written my own custom ICommand class for a WPF application, in which I invoked CanExecuteChanged directly in the first place like this.

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

    My WPF application makes heavy use of different threads and when the above method is called from another thread then the main UI thread, it throws no error, it is just kind of ignored. It was getting even worse, when I found out, that all code lines inside the calling method were skipped, which led to strange results.

    I don't know exactly, but I guess the reason was, that CanExecuteChanged led to changes in my UI, which must not be changed from another thread.

    However - the moment when I changed my ICommand to CommandManager.InvalidateRequerySuggested(), there was no more problem. It seems that CommandManager.InvalidateRequerySuggested() can be called from any thread and the UI still gets updated.

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
    
    public void RaiseCanExecuteChanged()
    {
        CommandManager.InvalidateRequerySuggested();
    }
    

    I thought this could be a valueable answer, because I debugged this issue for 3 hours, before I came to this solution. The problem finding this issue was, that there were no errors thrown while debugging. The code was just skipped. Very strange behaviour.

    0 讨论(0)
提交回复
热议问题