DelegateCommand class

Simplifies commands for ViewModels by the MVVM pattern. Provides an ICommand implementation which relays the Execute and CanExecute method to the specified delegates.

The problem

Besides data binding between the View and the ViewModel layer of the MVVM pattern, which represents rather ongoing states, Views must also trigger actions in the ViewModel, that is events that occur at a point in time. The .NET framework provides the ICommand interface for that task, it executes a command and tells whether it is currently available.

In order to implement that interface, one must create a separate class for each command that only contains the logic of that one command. In extensive user interfaces that makes a lot of classes, some with just a few lines of code. Moreover, these classes cannot access the internal state of the ViewModel, which is what they should work on most of the time.

The solution

To simplify that there’s the DelegateCommand class, sometimes also called RelayCommand. This class implements the ICommand interface but does not contain the command logic itself but instead only a delegate that runs it. This delegate, a method, is specified in the DelegateCommand constructor. This method is normally located in the same ViewModel class that also provides the command. Many short methods are thereby also in the class they should work with, e. g. modify their properties that in turn are displayed on the UI through data binding.

Besides delegates for the two methods Execute and CanExecute, each with an object parameter, this class also features overloads that don’t require a parameter, and additional helper methods. TryExecute for instance invokes Execute only if CanExecute returns true. As an alternative to calling the CanExecute method, the IsEnabled property can be set. The RaiseCanExecuteChanged method raises the same-named event to re-evaluate the command’s availability; RaiseCanExecuteChangedAsync defers the event. The static property DelegateCommand.Disabled provides a command that is always disabled and does nothing.

Compatibility: .NET Version 4.0 or newer

Example

The following sample class shows a ViewModel with commands:

public class MainViewModel : ViewModelBase
{
    // Declaration of all commands for this ViewModel as public properties
    public DelegateCommand OpenFileCommand { get; private set; }
    public DelegateCommand SaveCommand { get; private set; }
    public DelegateCommand SaveAsCommand { get; private set; }
    public DelegateCommand PrintCommand { get; private set; }
    public DelegateCommand QuitCommand { get; private set; }
   
    // Constructor
    public MainViewModel()
    {
        // Initialisation of the commands, each with a handler method and optionally
        // an implementation for CanExecute
        OpenFileCommand = new DelegateCommand(OnOpenFile);
        SaveCommand = new DelegateCommand(OnSave, CanSave);
        SaveAsCommand = new DelegateCommand(OnSaveAs, CanSave);
        // Printing is not yet supported, so it should always be disabled
        PrintCommand = DelegateCommand.Disabled;
        QuitCommand = new DelegateCommand(OnQuit);
    }
   
    // Method that is called when a file should be loaded
    private void OnOpenFile()
    {
        LoadedFile = AskForFile();
       
        // The Save commands are now available, their executability should now
        // be re-evaluated to update UI elements
        SaveCommand.RaiseCanExecuteChanged();
        SaveAsCommand.RaiseCanExecuteChanged();
       
        // Instead of implementing a CanExecute method a command can also be
        // activated and deactivated by a property
        QuitCommand.IsEnabled = false;
    }

    // Method that determines whether files can be saved.
    // In this example, both save commands share the same method.
    private bool CanSave()
    {
        // Saving is possible, when a file has been loaded
        return LoadedFile != null;
    }
   
    private void OnSave()
    {
        WriteFile(LoadedFile);
    }
   
    private void OnSaveAs()
    {
        LoadedFile.FileName = newFileName;
        // The save command is reused and executed, when it can be executed
        // right now. Otherwise, nothing happens.
        SaveCommand.TryExecute();
    }
   
    private void OnQuit()
    {
        if (LoadedFile.IsModified)
        {
            AskUserToSave();
        }
        else
        {
            CloseApplication();
        }
    }
}

Download

DelegateCommand.cs10.3 KiBSource code of the DelegateCommand class

Licence and terms of use

Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty. (GNU All-Permissive licence)

Statistic data

  • Created on 2012-07-09, updated on 2016-08-28.
  • Ca. 170 lines of code, estimated development costs: 170 - 680 €