How does CommandManager.RequerySuggested work?

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.


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)