CommandManager.InvalidateRequerySuggested() isn't fast enough. What can I do?

Viewed 22320

Short Version

Calls to CommandManager.InvalidateRequerySuggested() take far longer to take effect than I would like (1-2 second delay before UI controls become disabled).

Long Version

I have a system where I submit tasks to a background-thread based task processor. This submit happens on the WPF UI thread.

When this submit happens, the object that manages my background thread does two things:

  1. It raises a "busy" event (still on the UI thread) that several view models respond to; when they receive this event, they set an IsEnabled flag on themselves to false. Controls in my views, which are databound to this property, are immediately grayed out, which is what I would expect.

  2. It informs my WPF ICommand objects that they should not be allowed to execute (again, still on the UI thread). Because there is nothing like INotifyPropertyChanged for ICommand objects, I am forced to call CommandManager.InvalidateRequerySuggested() to force WPF to reconsider all of my command objects' CanExecute states (yes, I actually do need to do this: otherwise, none of these controls become disabled). Unlike item 1, though, it takes a significantly longer time for my buttons/menu items/etc that are using ICommand objects to visually change to a disabled state than it does for the UI controls that have their IsEnabled property manually set.

The problem is, from a UX point of view, this looks awful; half of my controls are immediately grayed out (because their IsEnabled property is set to false), and then a full 1-2 seconds later, the other half of my controls follow suit (because their CanExecute methods are finally re-evaluated).

So, part 1 of my question:
As silly as it sounds to ask, is there a way I can make CommandManager.InvalidateRequerySuggested() do it's job faster? I suspect that there isn't.

Fair enough, part 2 of my question:
How can I work around this? I'd prefer all of my controls be disabled at the same time. It just looks unprofessional and awkward otherwise. Any ideas? :-)

7 Answers

Try writing your own binding that calls your RaiseCanExecuteChanged() within converts? it is easier

Just to clarify:

  1. You want to fire an update of CanExecute when Command property changed
  2. Create your own binding class that detect changes in the Command property and then calls RaiseCanExecuteChanged()
  3. Use this binding in CommandParameter

Worked for me.

Related