CommandBindings in MVVM

Anyone who has tried to implement RoutedCommands in WPF using M-V-VM has undoubtedly run into issues. Commands (non-UI commands that is) should be implemented in the ViewModel. For instance if I needed to save a CustomerViewModel then I would implement that as a command directly on my CustomerViewModel. However if I wanted to pop up a window to show the users addresses I would implement a ShowCustomerAddress command directly in the view since this a UI specific function.

The problem lies in the way that RoutedCommands find their associated CommandBindings. In order for a command to be executed it has to have a CommandBinding which tells it how to handle the Executed and CanExecute events. When you associate a control with a command it walks up the logical tree to find the first command binding associated with it. A typical scenario would look like this:

<UserControl>
<UserControl.CommandBindings>
<CommandBinding Command="ApplicationCommands.Save" CanExecute="Save_CanExecute" Executed="Save_Executed" />
</UserControl.CommandBindings>

<Button Command=”ApplicationCommands.Save” Content=”Save” />
</UserControl>

This approach forces us to define the behavior of of the command directly in our view, when really that logic should be in the ViewModel. So how do we get the the View to look for the CommandBindings in the ViewModel instead of the baked in behavior of searching up the logical tree? Well, we can’t. So instead, we need a way to get the CommandBindings out of the ViewModel and into the View. The first thing we need is a CommandBindingCollection property in our ViewModel:

private readonly CommandBindingCollection _CommandBindings;
public CommandBindingCollection CommandBindings
{
   get
   {
      return _CommandBindings;
   }
}

Now we create our CommandBindings and add them to the CommandBinding property we created:

public CustomerViewModel(Customer model)
{
//Create a command binding for the Save command
CommandBinding saveBinding = new CommandBinding(ApplicationCommands.Save, SaveExecuted, SaveCanExecute);

//Register the binding to the class
CommandManager.RegisterClassCommandBinding(typeof(CustomerViewModel), saveBinding);

//Adds the binding to the CommandBindingCollection
CommandBindings.Add(saveBinding);
}

Now with a little Attached Property goodness we add the commandbindings of our ViewModel to our View:

public static DependencyProperty RegisterCommandBindingsProperty =  DependencyProperty.RegisterAttached("RegisterCommandBindings", typeof(CommandBindingCollection), typeof(AttachedProperties), new PropertyMetadata(null, OnRegisterCommandBindingChanged));

public static void SetRegisterCommandBindings(UIElement element, CommandBindingCollection value)
{
if(element != null)
element.SetValue(RegisterCommandBindingsProperty, value);
}
public static CommandBindingCollection GetRegisterCommandBindings(UIElement element)
{
return (element != null ? (CommandBindingCollection)element.GetValue(RegisterCommandBindingsProperty) : null);
}
private static void OnRegisterCommandBindingChanged
(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
UIElement element = sender as UIElement;
if (element != null)
{
CommandBindingCollection bindings = e.NewValue as CommandBindingCollection;
if (bindings != null)
{
element.CommandBindings.AddRange(bindings);
}
}
}

This is how you would use it in the view:

<UserControl local:AttachedProperties.
RegisterCommandBindings="Binding CommandBindings}" >

image

Conclusion

There are few other examples of how to do this like Josh Smith posted on CodePlex, but I think this is a much more straightforward approach and requires less code. I really hope this helps someone dealing with the same issue. If you think there is a better way, please let me know.

Code

There is a full example that you can download here. Be sure to change the file extension from .doc to .zip.
kick it on DotNetKicks.com

About these ads

18 Responses to CommandBindings in MVVM

  1. Richard says:

    I really like the neatness of this design – I wasn’t entirely comfortable with the replacement of standard CommandBindings that Josh proposes and the declarative nature of it makes it obvious from the Xaml exactly where the CommandBindings are coming from. Many thanks for sharing!

  2. micahlmartin says:

    Glad I was able to help.

  3. Shaun says:

    This worked perfectly. Thanks!

  4. Steve says:

    nice.. but. can you use that with custom commands.. i..e those not in the ApplicationCommands class.. if so would you be able to prove an example? (i cant get it to work) thanks.

  5. Karl says:

    Hello Martin,

    I have a question: How can I use this nice solution with a custom command? I´m new to C# and MVVM, so sorry if the question is a little studip ;)

  6. Henrique Clausing says:

    I can’t download de code example. I’ve tried t use in my application, but don’t work. Please help me. Thanks.

  7. Jasper says:

    Thank you for the nice article…

    I have a question, may be this question is out of the article scope but I would like to ask you anyway…

    I was wondering why we need to have CommandBindings at all.. when we can use a normal command (delgate command)… ?

  8. Jasper says:

    I mean in the ViewModel… In general CommandBindings make sense..

  9. New2 says:

    I’m very new to WPF and MVVM, but this approach seems nice as well:

    http://www.codeproject.com/KB/WPF/MVVMForDummies.aspx

    The ViewModel class has an ICommand property that you create a Binding to.

  10. Kevin Smith says:

    I like this approach too. There are a number of ways of doing this but this seems by far the most straight forward and the one that we ended up using…Just wish I had read this article first!

  11. Wolfgang says:

    But how did you solve the problem with custom commands. I didn’t get this to work either…

  12. Anonymous says:

    I also like this approach. Thanks for sharing it.

  13. [...] I stumbled upon this blog post by Michal Martin: CommandBindings in MVVM. In it, Michal describes an attached property that adds all the command bindings in a ViewModel to [...]

  14. Anonymous says:

    Thanks, this approach looks like it will work for me.

  15. Some time today I trapped an exception that indicates that the CanExecuteEventArgs was null, therefor setting e.CanExecute=true threw a null reference exception. I have not yet been able to reproduce it beyond the initial instance so I am not sure how big of a deal this is.

    Can you think of any reason this might occur? Having zero issues with this otherwise.

  16. baby shop says:

    baby shop…

    [...]CommandBindings in MVVM « {Coding Context}[...]…

  17. Thanks to this blog I’ve been using this technique for years. However, I only realized that it doesn’t seem necessary to register the commands with the CommandManager.

    In fact, doing so seems to create a memory leak if the command references the ViewModel (the VM is unable to be disposed). This is because the CommandManager is holding an instance of the VM even after the VM is no longer needed.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: