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.
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?
Originally posted by Morgan Skinner on 24th June here https://blogs.msdn.com/b/morgan/archive/2010/06/24/simplifying-commands-in-mvvm-and-wpf.aspx