Only invoke single command's attached controls??

Oct 8, 2009 at 5:27 PM

Josh, been thinking a bit about the behavior of CommandManager, it's InvalidateRequerySuggested and the implementation of RelayCommand (and for that matter some other similar command implementations).

If I understand it correctly, at the moment, the only way to raise the ICommand.CanExecuteChanged event is to call CommandManager.InvalidateRequerySuggested?

The thing that's always bothered me a little with this is that it seems like overkill - whenever some state change occurs which we know changes the canexecute state for a single command, we end up, if I understand things correctly, being forced to requery *all* command objects.

The question I have is - why can't we just update the state for the single affected command? If I understand things correctly, what's happening is the controls which are using the command have handlers that are attached to the command's ICommand.CanExecuteChanged event, and are updating their state (e.g. button enabled/disabled) in response to this event.

Wouldn't it then be better to provide a method that allow raising this event directly on the command class?

I would think this would require an additional change - the command class would have to keep it's own list of registered event handlers for the CanExecuteChanged event instead of purely delegating registration/deregistration to the CommandManager.RequerySuggested event. It would of course still need to register itself with the RequerySuggested event and propogate these notifications to it's handlers.

Am I off-base with this?  Maybe it's just not worth it, I guess you could say don't prematurely optimize, and if you did have a CanExecute delegate which was taking a significant time to execute, you could always implement some kind of caching algorithm to avoid invocation when state has not changed.

Maybe it's just me, but it is one think that's kind of concerned me.



Oct 8, 2009 at 5:38 PM

WPF has a known issue where ICommandSource objects (like Button) will cause memory leaks due to not unhooking the CanExecuteChanged event of their Command.  Since CommandManager uses the Weak Event pattern, the leak is avoided when using its RequerySuggested event.  That workaround is the reason why RelayCommand uses CommandManager instead of the approach you suggest.


Oct 8, 2009 at 7:55 PM

Josh, if I was to implement the weak event pattern on the command class would this handle this issue?

I'm using these command classes purely within viewmodels, so I would expect the bindings from the views to prevent incorrect collection of the command objects, either as a result of the bindings from the views to the commands or as a result of the bindings from the view to the viewmodel and the viewmodel's references to it's child command objects.

Maybe it's not really worth it, but since it's bugging me, do you think it would work??  ;)




Oct 8, 2009 at 7:59 PM

The fact that the View elements are bound to a command in the ViewModel does not mean that the ICommandSource doesn't hook the CanExecuteChanged event of the command.  Binding the Command property of a Button is just another way of setting that property, which eventually causes the event to be hooked.  Implementing your own weak event pattern would probably work, but I'm lazy and took the easy way out (CommandManager). ;)


Oct 8, 2009 at 8:16 PM

Thanks Josh,