Simplifying RelayCommand/DelegateCommand in WPF MVVM ViewModels

Ben Schoepke picture Ben Schoepke · Jun 24, 2010 · Viewed 18.4k times · Source

If you're doing MVVM and using commands, you'll often see ICommand properties on the ViewModel that are backed by private RelayCommand or DelegateCommand fields, like this example from the original MVVM article on MSDN:

RelayCommand _saveCommand;
public ICommand SaveCommand
{
    get
    {
        if (_saveCommand == null)
        {
            _saveCommand = new RelayCommand(param => this.Save(),
                param => this.CanSave );
        }
        return _saveCommand;
    }
}

However, this is a lot of clutter, and makes setting up new commands rather tedious (I work with some veteran WinForms developers who balk at all this typing). So I wanted to simplify it and dug in a little. I set a breakpoint at the first line of the get{} block and saw that it only got hit when my app was first loaded--I can later fire off as many commands as I want and this breakpoint never gets hit--so I wanted to simplify this to remove some clutter from my ViewModels and noticed that the following code works the same:

public ICommand SaveCommand
{
    get
    {
        return new RelayCommand(param => this.Save(), param => this.CanSave );
    }
}

However, I don't know enough about C# or the garbage collector to know if this could cause problems, such as generating excessive garbage in some cases. Will this pose any problems?

Answer

Simon D. picture Simon D. · Jun 25, 2010

This is exactly the same as if you would offer a - say integer - property that calculates some constant value. You can either calculate it for each call on the get-method or you can create it on the first call and then cache it, in order to return the cached value for later calls. So if the getter is called at most once, it does make no difference at all, if it is called often, you will lose some (not much) performance, but you won't get real trouble.

I personally like to abbreviate the MSDN-way like this:

RelayCommand _saveCommand;
public ICommand SaveCommand
{
  get
  {
    return _saveCommand ?? (_saveCommand = new RelayCommand(param => this.Save(),
                                                            param => this.CanSave ));
  }
}