47

The MSDN only states that

Occurs when the CommandManager detects conditions that might change the ability of a command to execute.

However I can't seem to find any traces of how this works, what I should be aware of / avoid etc... Does it just listen for input? (i.e.: mouse moves, keys pressed and so on)

Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
Andrei Rînea
  • 20,288
  • 17
  • 117
  • 166

2 Answers2

54

I cannot tell you exactly what events the CommandManager listens to. However, I can tell you that you should be careful when using the CommandManager in connection with asynchronous operations. I had the following problem when I used the CommandManager in my ICommand implementations:

I had a button bound to an ICommand which triggered an asynchronous operation which increased a value. Now, the button/ICommand should be disabled (i.e. its CanExecute() method should return false) if the value had reached a certain limit. The problem was: The CommandManager called my CanExecute() method right after the button had been clicked and the asynchronous operation had been started. This asynchronous operation did not take long, but it was long enough to get its result after the CommandManager's check, so that the limit check in CanExecute() was done using the old value. Therefore, the button remained enabled although the limit was actually reached. The funny thing was, after you clicked anywhere in the UI, the button now got disabled because the CommandManager checked the ICommand once again and now the new value was checked against the limit. Actually, I think the CommandManager waited around 50ms after the button click until it performed the check of the ICommand, but I am not quite sure about that.

My solution was to force the CommandManager to check the ICommand again by calling the CommandManager.InvalidateRequerySuggested method in my ViewModel right after I received the result of the async operation.
Update: Please note that this method must be called on the UI thread, otherwise it will have no effect! (Thanks to midspace for this comment)

Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
gehho
  • 9,049
  • 3
  • 45
  • 59
  • 13
    It should be noted since you are running an Async call, that the CommandManager.InvalidateRequerySuggested() must be called in the UI thread, otherwise from personal experience, it does nothing. – midspace Mar 18 '11 at 02:44
  • 4
    It seems to me that in this circumstance you should not use CommandManager.RequerySuggested as the SOLE trigger for your CanExecuteChanged event. Clearly your code knows when the async operation completes. It should use that completion to raise your command's CanExecuteChanged. It may be that CommandManager.RequerySuggested has great ideas AS WELL so maybe you should use those in addition. – RichardHowells May 15 '14 at 14:34
5

In that case .NET Reference Source is your friend. Although its badly commented you can still get some ideas about the internal processing.

In the internal CommandDevice class you find a method PostProcessInput which invokes the InvalidateRequerySuggested. The name of this method lets assume that the InvalidateRequerySuggested method is invoked on every input event. I'm sure there is further processing and filtering so that your CanExecute method is actually not invoked on every call to InvalidateRequerySuggested.

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Sam
  • 1,301
  • 1
  • 17
  • 26
  • The URL has changed to https://referencesource.microsoft.com/#PresentationCore/Core/CSharp/System/Windows/Input/Command/CommandDevice.cs (I couldn't submit the edit, because it involves less than 6 characters. – Mike Rosoft Oct 09 '19 at 08:59
  • 1
    @MikeRosoft I made your change. – StayOnTarget May 12 '20 at 19:19