Reputation: 17402
Our UI currently has a lot of controls that are bound to commands with some complex CanExecutes
. The problem we are facing is that whenever CommandManager
determines that the UI needs to be re-evaulated, all commands run their CanExecute
, which in turn, causes quite a performance hit for specific scenarios.
Reading this post: How does CommandManager.RequerySuggested work?
It seems that the CommandManager
will re-evaulate on simple key down, mouse move events, etc. Is there a way to prevent this from happening, and instead, have the command manager re-evaluate when manually invoked?
Upvotes: 3
Views: 1184
Reputation: 13177
A solution might be to implement a simpler version of the RelayCommand
class that simply stores the event handlers itself and exposes a public method to fire them when appropriate:
public class RelayCommand : ICommand
{
public event EventHandler CanExecuteChanged;
// Further ICommand implementation omitted...
public void Invalidate()
{
var handler = this.CanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
You then call the following in your viewModel to re-evaluate the command:
fooCommand.Invalidate();
Of course, this leaves you with the opposite problem that you now have to manually re-evaluate all commands...
Edit
To elaborate on the comments, most RelayCommand
's implement the CanExecuteChanged
event like this:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
When the UI subscribes to the command's CanExecuteChanged
event it is actually being indirectly subscribed to the CommandManager.RequerySuggested
event which is why your CanExecute
method is being called every time the CommandManager
suggest a re-query.
The simpler RelayCommand
I have suggested avoids this problem by not subscribing to the CommandManager.RequerySuggested
event.
Upvotes: 1