Allowing CommandManager to query your ICommand objects

One of the great parts about commands in WPF is that they know if they can currently execute or not. When they cannot execute, the control(s) that are set to execute the command will be disabled automatically. For example, if your application has no changed data, the Save toolbar button will automatically be disabled, assuming its Command property is set to the Save command.

WPF will automatically ask all of the commands being used in your UI if they can execute. This happens at various times, such as when input focus shifts to another control, an item is selected in a list, etc. You can also programmatically trigger this to happen by calling the CommandManager’s InvalidateRequerySuggested static method. This all seems magical, dreamy, and almost too good to be true.

Here’s the hitch: this beautiful system of commands automatically notifying the UI that they cannot execute only works out-of-the-box for RoutedCommands. If you simply implement ICommand and hook up, say, a Button’s Command property to reference that non-routed command, suddenly the Magical Love Machine comes to a grinding and screeching halt. Why? Because by default WPF has no idea that your custom ICommand objects exist. How would it?

Fortunately there is an easy solution to this problem. In your ICommand implementation, you make the CanExecuteChanged event hook the CommandManager’s RequerySuggested event. I lifted this little trick straight from Reflector, as I perused the RoutedCommand class…

class MyCommand : ICommand
{
public bool CanExecute(object parameter)
{
return maybeTrueOrFalse;
}

public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}

public void Execute(object parameter)
{
// Do something awesome.
}
}

About these ads

32 Responses to Allowing CommandManager to query your ICommand objects

  1. sacha says:

    Neat, got to love Reflector

  2. Josh Smith says:

    That’s the truth!

  3. PierreMF says:

    This is really magic: yesterday, I was wondering how WPF polls RoutedUICommand objects to update the UI state… and found no solution. So I was thinking about calling ICommand.RaiseCanExecuteChanged() each time the command state changes. Not very elegant…

    So, you save my life !! Thank you !

    It demonstrates that WPF world is exactly like the picture in this post ;)

    {I am using my own ICommand objects (based on the great work of the Prism project: DelegateCommand and CompositeCommand) to implement undo/redo, app scripting, elegant command routing…}

  4. Josh Smith says:

    That’s great! Have fun, Pierre. :D

  5. Another great one, Josh :)

    Let me add that RequerySuggested can be a little heavy in some cases, I prefer to add a little “Refresh” method to Commands that trigeers the CanExecuteChanged in case the change happens in the app itself, like so:

    http://www.planet-xaml.net/page.aspx?article=8

    (In a direct implementation of ICommand it looks simpler of course)

    Cheers
    Florian

  6. Josh Smith says:

    Florian,

    Using a “manual” approach like that (where the command object raises its CanExecuteChanged event) requires your code to correctly refresh all of the relevant commands at the right time. The actual runtime overhead associated with using the RequerySuggested approach is extremely small (provided your can-execute logic doesn’t call a web service!) so I think the simplicity and lack of maintenance involved with that approach is more appealing than the nominal perf increase you might gain by using the manual approach.

    With that said, there’s nothing stopping you from using both techniques for the same command.

    Josh

  7. xamlresx says:

    Nice trick! I’ll try that out.

  8. Alex D says:

    Josh you are such pussy. You waste your time with UI blog. All real programmer know the UI is for stupid little girl. Take your dick out of hand and do real programming. Then you will see how stupid you are. Take my word for it, you are stupid asshole for all this UI shit. Why dont you get job as janitor? ;)

    /alex

  9. Josh Smith says:

    Alex,

    Sorry, your comment is far too intelligent for a mere UI programmer, such as myself, to understand. Therefore, I’m going to blissfully ignore it. Have a great day, your Majesty.

    Josh

  10. Craig says:

    Alex D:

    Really? Please tell me this is a joke…

    You know, your comment reminds me of one of my favorite quotes, “it’s better to remain silent and let everyone think you are a wise man than to open it and prove otherwise.” Even if this is a joke, you sir, have proven your point well.

    I also find interesting that you are here taking cheap shots at an accomplished professional when you didn’t event provide a URL in your comment. So where’s your contribution to the development community, Alex?

    Craig Shoemaker

  11. marlongrech says:

    Alex, who do you think you are to talk to the Rockstar like this!

    You say that UI programming is shit and for pussies then can you please tell why people like Martin Fowler give so much interest in UI… Do you know what are Design Patterns? If yes why do people invest so much time in doing UI Design Patterns? Are you perhaps saying that even Martin Fowler is a pussy?

    Alex, go to hell and stay there….

  12. Alex D says:

    You people are pathitic. I leave true comment and next thing there is 3 little pussy comment showing how much pussy you are. Real programmer dont have time for this shit. We are to busy doing genuis things like neuralnet not making imagination of being real programmer.

    Josh – You are not that stupid. Come on. Dont play dum with me.

    Criag – Shut up with the whines and that. Its pathetic. I dont need URL to prove myself.

    marlongrech – I dont care about the Martin Fowler. Real programmer smarter then that. UI patterns only help the UI idiots because they need it. Trust me on that, it is true.

  13. Josh Smith says:

    Alex,

    Please stop trolling on my blog. Go back to doing your “genuis [sic] things.”

    Josh

  14. marlongrech says:

    “I dont care about the Martin Fowler”

    How can you call yourself a developer….. LOL…. stop making fun of yourself…..

  15. sacha says:

    Alex I am a big fan of Joshs and also like UI programming but also know how to do computer vision, neural networks, data mining in fact my degree was AI in which I got a 1st class degree, but I still find some of the stuff Josh does simply genious.

    If you took the time to try and understand UI (WPF in particular) you would realise component manufacturers and UI experts have to deal with loads of intracies.

    I feel you comment just doesnt stand up, I mean like I say NNs so what.

  16. sacha says:

    Alex one more thought if you dont like Joshs blog, dont read it, its not for you, its for people that want to learn WPF

  17. It was just a perception, I didn’t profile it. E.g. when you have a lot of command-bound buttons with complex styles on a page, each of them will be rerendered on RequerySuggested?
    Maybe a good rule of thumb would be: if something in the UI triggers the state change, suggest a requery, if the change is triggered by the BLL (e.g. a callback ) , fire manually. Would you agree?

  18. Josh Smith says:

    Florian,

    I think we should rely on RequerySuggested, but get involved manually when necessary. The question then becomes, should “manually” mean calling CommandManager.InvalidateRequerySuggested() or telling a specific command to raise its CanExecuteChanged event. I lean more toward the former, since usually more than one command needs to be refreshed when something happens to cause a command to change its can-execute status.

    Josh

  19. karlagius says:

    Fowler… not real programmer? … omg … DUDE! You mean millions of developers around the world have got it wrong all along?

    Maybe you should also call the publishers of Collins English Dictionary and tell them that they got their spelling wrong. While you’re doing that, how about dropping by at the UN headquarters and telling them that in reality the best way to initiate communication with a group of total strangers is to call them a bunch of pussies.

    You’re right in one point, you don’t need a URL to prove yourself. I’m sure all the other patients love you just the way you are, and that’s the important thing right?

  20. Reuben says:

    [@Alex D.] Seems like there is always a vacancy for trolls, especially on forums. How do you consider yourself to be a self-acclaimed “genuis” ? Especially with the way you write. You seem to speak fluent moron. How can you expect to be taken seriously in this field and not care about a person like Martin Fowler? He is a very important person in Software Engineering. Or do you consider all of Software Engineering to be useless? It is like saying that algorithms are not useful, or that you do not care about the Donald Knuth.
    Stop being such a fan boy, and broaden your horizons.
    Also realize that computers are not just for people that know how to use terminals and command prompts, but also to enhance everyday use of normal people.
    And that is where UI comes in handy. If you have ever had a program you built used by more than one person (you), then you would know that people appreciate UI. (Imaginary girlfriends do not count.)

  21. Josh Smith says:

    Oh, this is rich! Alex D is a mixed blessing… :D

  22. Hi Josh!!
    Wow! this post clarified me that ICommand itself would be good enough for the MVVM pattern!

  23. Josh Smith says:

    That’s great, Quang! I think that plain old ICommand does not get enough attention, because routed commands are written about more often.

  24. Vladislav Spivak says:

    Well, people, RoutedCommands is pretty good facility, but….
    To my mind, there is some unlikely good behaviour of RoutedCommand: CanExecute fires regardless of ICommandSource state. Consider that you have some serious app with many routed commands defined and binded, but relevant ICommandSource’s are invisible or disabled most of the time. In such case you expect that CanExecute will be fired only when ICommandSource is enabled and visible: standalone (without subsequent Execute call) CanExecute mostly intended to update ICommandSource’s state (for example, to make Button disabled on false). Actually, CanExecute fires on every minor UI change. This can lead to huge performance impact in case you have some not trivial calculations inside CanExecute. One of the best examples of this behavior is ScrollViewer. You can define it with both Vertical and Horizontal ScrollBarVisibilities set to “Disabled”, but every time you change something inside this ScrollViewer, CanExecute will fire on all 8 (yea, each ScrollBar have 4) ICommandSources, regardless of the fact, that both bars are disabled.
    So, my conclusions:
    1. Keep your CanExecute implementations as lightweight as you can
    2. Try to assign RoutedCommands to ICommandSources in loosely manner, for example in Trigger that looks for both Visibility=Visible and IsEnabled=true

    Generally, I feel that this is bug by design, but if somebody knows some good reason of this, I will be happy to know.

    Sorry for bad English.

  25. Josh Smith says:

    Thanks for the thoughtful feedback, Vladislav. You raise some very interesting points.

    Josh

  26. Tonko says:

    I had CanExecute breakpoint hits on objects that were to be garbage collected since like three weeks ago :) , confusing my debugging to no end. So one must be careful to unregister the commands when object instance holding a reference to it goes to garbage.

    I wish there was some ‘automatic’ way to prevent the above form happening, but all my reading about weak references didn’t help. Maybe somebody will stumble upon the trick to do it one day – otherwise Josh, as usual, thanks for extremelly helpful bits like this one.

  27. Pablo says:

    Hi Josh! I had been reading a lot of your post in codeproject. I am trying to implement the MVC but my client asked to me we have some adapters and just one controller. Like a multiple document app. This will be a distributed app, the controller and the adapters could be on different machines. He alse asked me the adpaters send commands to the controller thru some comunication framework. I am thinking in use the routed commands that wpf gives us. But my adapters are not UIElements, for that reason when I am trying to Execute my command the CanExecute is false all the time.
    Can you help me? Do you thing is a good idea use the wpf commands between two not UI layers?

  28. Josh Smith says:

    Pablo,

    Routed commands only work in the element tree, since they use routed events to send execution notifications. You can use normal ICommands, unless you are aiming for UI platform-independence, in which case you should roll your own command implementation.

    Josh

  29. Pablo says:

    Josh,
    I apreciate your answer!
    I need to thing a little more about the app architecture, I thought the adapters could access to my commands in the controller layers and execute them by hand when something happens, also the event handlers should be are in the controller component, and get this way to communicate these two components.
    Pablo

  30. NgocLuu says:

    You saved my life!
    Thank you, Josh!

  31. Daniel G. says:

    @Tonko:
    You have to be very careful implementing CanExecute to prevent memory leaks.
    Apparently, WPF expects this event to be implemented as a weak event. That means, the event should use a List<WeakReference> for the delegates, so that objects don’t have to unregister (because they don’t!).
    Interestingly, this means a WeakReference to the delegate, not to the listening object – the listening object must keep a reference to the its own delegate instance so that the delegate doesn’t get garbage collected even though the listening object is still reachable.
    CommandManager.RequerySuggested is such a weak event, so Josh’s code works fine.
    The default interface implementation generated by VS – a default C# event (“public EventHandler CanExecuteChanged;”) – will cause a memory leak!
    So basically, there are only two easy options:
    1) If CanExecute never changes and you don’t intend to fire the event, then don’t use a default event, use an event that doesn’t store the delegates.
    public event EventHandler CanExecuteChanged {
    add { }
    remove { }
    }
    2) If CanExecute changes, use the CommandManager. (Josh’s code)

    Anything else must work with WeakReferences to prevent memory leaks.

Follow

Get every new post delivered to your Inbox.

Join 288 other followers

%d bloggers like this: