Condividi tramite


Simplifying commands in MVVM and WPF

I’ve been using MVVM since I started WPF (I was a latecomer to the beauty that is WPF) and one of the things that’s always irked me is the amount of code you need to write in order to expose a command. I’ll typically write something like the following in order to create a command that I can bind to from the UI…

 public class WibbleViewModel : BaseViewModel
{
    public WibbleViewModel()
    {
        _thisCommand = new DelegateCommand(x => 
            MessageBox.Show("You clicked ThisCommand"));
    }

    public ICommand ThisCommand
    {
        get { return _thisCommand; }
    }

    private ICommand _thisCommand;
}

The BaseViewModel class is one from my good chum iJosh. Anyhow, there’s a lot of code that I have to write in order to expose just one command (well, I think so anyway, aren’t computers supposed to make life easier?). Today I was writing yet another WPF app (I tend to do a lot of demos with my customers) and after writing the above yet again I had a brainwave.

ICustomTypeDescriptor to the rescue

Rather than repeat this code ad-infinitum for each command (and lets face it, WPF apps generally have lots of commands), I crufted up a sample using a custom type descriptor. If you don’t know, .NET has supported the ICustomTypeDescriptor interface since the first version (indeed I wrote an article about extending the Windows Forms property grid that used ICustomTypeDescriptor on 30/11/2001!). What this interface allows you to do is to synthesize metadata about an object instance. You can for example add attributes to the metadata for an object using this interface. You can also add fields. But for the purposes of this article, I’m adding properties.

What’s the good of that you might say?

Well, what I’m trying to do is simplify the number of lines of code I have to write in order to expose commands on a given View Model. Now, when I bind to a command from the XAML I’d typically type in an expressions such as the following…

 <StackPanel Grid.Column="1" Orientation="Vertical">
    <Button Content="New Expense Claim" Margin="30,10"
        Command="{Binding NewExpenseCommand}"  />
    <Separator/>
    <Button Content="Approve Claim" Margin="30,10"
        Command="{Binding ApproveExpenseCommand}"  />
    <Button Content="Reject Claim" Margin="30,10"
        Command="{Binding RejectExpenseCommand}"  />
</StackPanel>

Then for each of these 3 example commands I’d have to define a property getter, private variable etc etc. Now Binding in WPF is pretty clever, and it uses property descriptors in order to navigate to the value bound.

Less Code, More Smiles

So, all I should need to do is alter the syntax used in XAML and (with the assistance of a helper class) I could expose commands *without* all of the boilerplate code. I’d then have bindings setup as follows…

 <StackPanel Grid.Column="1" Orientation="Vertical">
    <Button Content="New Expense Claim" Margin="30,10"
        Command="{Binding Commands.NewExpenseCommand}"  />
    <Separator/>
    <Button Content="Approve Claim" Margin="30,10"
        Command="{Binding Commands.ApproveExpenseCommand}"  />
    <Button Content="Reject Claim" Margin="30,10"
        Command="{Binding Commands.RejectExpenseCommand}"  />
</StackPanel>

Note here that I’ve prefixed the name of each command with ‘Commands’. This is a property that I’ve exposed from my View Model that uses my CommandMap class (which you can grab at the end of the article). The entire code in my View Model to expose the three commands is as follows…

 public class WibbleViewModel : BaseViewModel
{
    public WibbleViewModel()
    {
        _commands = new CommandMap();
        _commands.AddCommand("NewExpenseCommand", 
            x => MessageBox.Show("Not yet implemented", "New Expense Claim"));
        _commands.AddCommand("ApproveExpenseCommand", 
            x => MessageBox.Show("Not yet implemented", "Approve Claim"));
        _commands.AddCommand("RejectExpenseCommand", 
            x => MessageBox.Show("Not yet implemented", "Reject Claim"));
    }

    /// <summary>
    /// Get the list of commands
    /// </summary>
    public CommandMap Commands
    {
        get { return _commands; }
    }
     private CommandMap _commands; 
 }

Here I’ve created an instance of the CommandMap class in my constructor, exposed this as a read-only property, and then created the actual commands in the simplest way possible by calling ‘AddCommand’. There are two overloads of AddCommand as shown below…

 public void AddCommand(string commandName, 
                       Action<object> executeMethod);

public void AddCommand(string commandName, 
                       Action<object> executeMethod, 
                       Predicate<object> canExecuteMethod);

The commandName argument is used to expose the ICommand to the {Binding} markup extension. If you remember, in the XAML I bound to Commands.NewExpenseCommand which, through the beauty of ICustomTypeDescriptor, ultimately gets me into my code that can return an ICommand instance. The {Binding} extension first looks for an object called Commands on the current DataContext. This gets me to my CommandMap class. The binding then asks for the NewExpenseCommand property, which is now running code in my custom type descriptor code. All I have to do is delve into a dictionary inside CommandMap that stores name/value pairs based on what I used for AddCommand, and I can synthesize a property called NewExpenseCommand (or anything else for that matter) which WPF will diligently bind to. Voila!

The executeMethod and canExecuteMethod properties can be supplied as Lambda functions, making your code nice and concise (under the covers I’ve reused a DelegateCommand object which I’ve been using for ages). And just for that extra bit of conciseness (if that’s a word!) I could move all of this stuff up into the BaseViewModel class. Saweet.

The Code

Please click on the following file to view or download the C# source code for the CommandMap class.

CommandMap.cs

This doesn’t have any other dependencies so you should be able to plug this in wherever you like with the minimum of fuss. The one enhancement I can think of at the moment is to cache the property descriptor collection returned from the GetProperties method of the CommandMapDescriptor class. This would require that the command collection was an observable collection and I’ve just not got round to that code as yet.

Let me know what you think – good/bad/ugly?

Comments

  • Anonymous
    June 23, 2010
    I'm all for less code and simplicity, so this is a win. The only downside is the magic strings.

  • Anonymous
    June 23, 2010
    Interesting approach. Unfortunately Silverlight can't take advantage of it but what else is new. I took a similar approach using attributes and methods. My BaseViewModel has a Commands property that is a dictionary and the base class scans methods of the derived class looking for a CommandAttribute. If it finds one, it creates a DelegateCommand targeting that method and adds it to the dictionary. Then binding in the view looks like (Button Command="{Binding Commands[Approve]}" /)

  • Anonymous
    June 24, 2010
    +1 for a clever approach. But I think the reada-testa-bility of the ViewModel would suffer as a result (and that, after all, is one of the main reasons for MVVM). It's now no longer clear what commands the ViewModel supports, and not as easy to access them in code. I've proposed my own reduced-boilerplate recipe on my blog: blog.functionalfun.net/.../wpf-mvvm-commands-new-reduced.html No reason that it wouldn't work on Silverlight either.

  • Anonymous
    June 24, 2010
    Have used the following is Silverlight, when Im lazy <Button Command="{Binding GenericCommand}" CommandParameter="NewExpense"/> <Button Command="{Binding GenericCommand}" CommandParameter="ApproveExpense"/> GenericCommand has a dictionary for Command and CanExecute When Im not so lazy I'll create a snippit or a add-in to do it properly

  • Anonymous
    June 24, 2010
    The comment has been removed

  • Anonymous
    June 25, 2010
    The comment has been removed

  • Anonymous
    June 26, 2010
    Here's using C# 4's dynamic objects to make the implementation almost trivial:    public class MyViewModel    {        private dynamic commands = new ExpandoObject();        public dynamic Commands { get { return commands; } }        public MyViewModel()        {            Commands.TestCommand = new DelegateCommand(x => MessageBox.Show("Test", "TaDa!"));        }    }

  • Anonymous
    June 29, 2010
    Another option is to use Actions - I've an implementation of InvokeMethodAction - to invoke methods in ViewModel direclty For WPF - http://bit.ly/8YhADa For Silverlight http://bit.ly/5ECaum

  • Anonymous
    July 07, 2010
    Hi Morgan, I absolutely loved ICustomTypeDescriptor. I have never heard of it and I really liked the possibilities this interface gives. However I don't think it's usage in this context (commands) is justified. Thanks for sharing this, I am sure I will use the interface for binding to dynamic properties somewhere, actually I had the requirement already some time ago.. Thanks, Kirill

  • Anonymous
    October 07, 2012
    I too like Less Code, More Smiles :) Nice Sample.