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:
-
It raises a “busy” event (still on the UI thread) that several view models respond to; when they receive this event, they set an
IsEnabledflag on themselves tofalse. Controls in my views, which are databound to this property, are immediately grayed out, which is what I would expect. -
It informs my WPF
ICommandobjects that they should not be allowed to execute (again, still on the UI thread). Because there is nothing likeINotifyPropertyChangedforICommandobjects, I am forced to callCommandManager.InvalidateRequerySuggested()to force WPF to reconsider all of my command objects’CanExecutestates (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 usingICommandobjects to visually change to a disabled state than it does for the UI controls that have theirIsEnabledproperty 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? 🙂
CommandManager.InvalidateRequerySuggested()tries to validate all commands, which is totally ineffective (and in your case slow) – on every change, you are asking every command to recheck itsCanExecute()!You’d need the command to know on which objects and properties is its
CanExecutedependent, and suggest requery only when they change. That way, if you change a property of an object, only commands that depend on it will change their state.This is how I solved the problem, but at first, a teaser:
The command is listening on
NotifyPropertyChangedevents from object that affect whether it can execute, and invokes the check only when a requery is needed.Now, a lot of code (part of our in-house framework) to do this:
I use
DelegateCommandfrom Prism, that looks like this:I have then written a
ListenOnextension method, that ‘binds’ the command to a property, and invokes itsRaiseCanExecuteChanged:You then need the following extension to
NotifyPropertyChangedwhere
INotifyPropertyChangedWithRaiseis this (it estabilishes standard interface for raising NotifyPropertyChanged events):Last piece of puzzle is this: