M-V-VM Building an ERP-system – part 4 of N – commanding
After part 3, we are getting ready to tie things together and as many might know, WPF contains the really nice ICommand interface that implements well with buttons, menus and inputbindings (go .Net 4.0). Back when I started out with WPF I used a lot of standalone implementations of the ICommand interface. It made for very nicely encapsulated commands, but there were problems. I put them into ResourceDictionaries for sharing them between views, but soon I had an overwhelming number of them, and naming became a problem. Also, maintainability proved troublesome. Having scattered business-logic scattered out into all these little classes that I couldn’t use DI (Dependency Injection) on proved a maintenance nightmare and ResourceDictionaries proved brittle (magic strings, anyone?). Testability wasn’t all that great either, and most of the commands were mostly doing boxing and un-boxing and IoC (Inversion of Control) resolution.
So, while a definete improvement over the old eventhandlers of Windows Forms, I wasn’t totally convinced it was the perfect solution – and then I stumbled upon the M-V-VM pattern (thanks to Josh Smith). This proved an eye-opener for me – binding to commands was a really neat trick – and the most important? I had functionality for views together in one spot. ‘What can I do with Customers in this view…? Oh look 4 commands in the CustomersViewModel – guess I can do those 4…’ Testing is a lot easier and I get the added bonus of one-place boxing and un-boxing. Wait a minute… I use the same CanExecute across commands? Well, not exactly – I wouldn’t want to introduce some sort of inheritance hierachy for something as simple as ICommands – no, enter the RelayCommand (again – thanks Josh).
Now, it may seem that Josh Smith is a demi-god of M-V-VM – and he is, but I do not agree with him in everything he does. I have read his article on MSDN, and I disagree on some of the choices he takes, but we do really different things, so that is to be expected. But you get to be the judge at which approach fits you better.
public class RelayCommand:ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public RelayCommand(Action<object> execute)
{
_execute = execute;}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;}
public void Execute(object parameter)
{
_execute(parameter);}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);}
public event CanExecuteChanged
{
add
{
if(_canExecute != null)
CommandManager.RequerySuggested += value;}
remove
{
if(_canExecute != null)
CommandManager.RequerySuggested -= value;}
}
If I had to point at one single class that has made the largest impact on my coding style – this is it. It has a bit of the functional programming that I’m still a beginner at, but realizing the potential of every day. In the ERP-system I’m about to construct, I will have 2-3 implementations of the ICommand interface – one of them being the RelayCommand. It saves me a lot of boiler-plate code (at least 8 lines per command – and that adds up when you have hundreds of commands). And DRY! Many commands will in the CanExecute method simply figure out if a parameter is of the correct type – and for a Customer – it is usually whether it is a customer… so, the four commands can share the same Predicate. I know it may seem like small pickings, but it was one of the few places, refactorings couldn’t really touch in standalone commands.
So – in the implementations of the first ViewModels, you will see a lot of RelayCommand’ing.
In part 5, I’ll finally start looking at the actual implementations of the ViewModels.
About the series:
The solutions introduced here are not entry-level material. You should understand generics and basic patterns to fully utilize the material presented. The solution represents about 3 years of experience working with one ERP-solution. Some of the choices taken are heavily influenced from the large-scale solution and may seem overkill for the simple examples here, but the idea is to show the end-result of my experience and hopefully you as the reader will at least see a new way of doing things. The solution is built in .Net 4.0 with heavy use of WPF’s capabilities. Here you can find the source-code for the series. You are free to use this code for any purpose, but it is presented as-is with no guarantees. Enjoy!
Goblincave » M-V-VM Building an ERP-system – part 5 of N – CustomersViewModel said,
June 6, 2010 at 22:27
[...] introduced commanding in part 4 and so far we have mostly been trying to get to the point where we can actually see something on [...]
Goblincave » M-V-VM Building an ERP-system – part 3 of N – the first ViewModels said,
June 9, 2010 at 9:13
[...] In Part 4, I’ll look at implementing commands. [...]