WPF: Command Factory


Many moons ago, I blogged about the Command System in WPF. Today I’m going to talk about a Factory Class that will create commands for you, taking in delegate functions as parameters. How this helps is reduce the amount of code you have to write, because the Command Factory takes care of that for you.

You only need to write your CanExecute and Execute methods in your ViewModel (if you’re using MVVM pattern) or Xaml code behind, and can directly databind to your controls, like Buttons. I’ve created two private Command classes, one that is generic and a plain old one. The generic one takes care of Commands that require Command Parameters. The generic one looks like this.

private class Command< T > : ICommand
{
    private Func< T, bool > _canExecuteAction;
    private Action< T > _executeAction;

    internal Command(Func< T, bool > canExecuteAction, Action< T > executeAction)
    {
        _canExecuteAction = canExecuteAction;
        _executeAction = executeAction;
    }

    #region ICommand Members

    public bool CanExecute(object parameter)
    {
        return _canExecuteAction((T)parameter);
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        _executeAction((T)parameter);
    }

    #endregion

    internal void OnCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }
    }
}

We make use of the new C# 3.0 delegate classes, Func<TResult, T> and Action<T>. If you are familiar with delegates, this won’t be new to you. These new generic classes provides lot of convenience for developers, where in the past you had to write them yourselves in .NET 2.0.

Below is the Factory method for getting a command.

public static ICommand CreateCommand(Func<bool> canExecuteAction, Action executeAction, out Action canExecuteChangedAction)
{
    Command command = new Command(canExecuteAction, executeAction);
    canExecuteChangedAction = command.OnCanExecuteChanged;
    return command;
}

There’s an out Action parameter you can specify, amongst some of the overloads provided. What this does is that the caller will get a reference of a delegate which will call the ICommand‘s CanExecuteChanged event, which in turns triggers a check of CanExecute of the command. Reason for doing this instead of allowing the caller to call a public method to do trigger the event is that you effectively lose the ability to use the ICommand interface. I would rather use the out parameter and leave the implementation ‘unpolluted’ so we can still program to the interface.

To hook this up, one option is to put it in your View‘s code behind. In the snippet below, we do this in the Window Loaded event.

void Window1_Loaded(object sender, RoutedEventArgs e)
{
    this.DataContext = this;
    this.Command = CommandFactory.CreateCommand(() => { return true; }, Command_Execute);
}

public ICommand Command { get; private set; }

private void Command_Execute()
{
    MessageBox.Show("Normal Command Executed", "Normal Command");
}

I used Lambda Expressions, to represent my Func<bool> input parameter, and that saves me from writing a method. Functional style programming in a static language…evolution is wonderful.

I’ve created a little demo application to demonstrate how to use do all these. It demonstrates how to hook up commands as it is, and one that takes in a Command Parameter. Hope this was helpful.

Download demo app here.

Download CommandFactory code file. (rename to .cs)

Share this post:

Advertisements
Posted in WPF. Tags: . 2 Comments »

2 Responses to “WPF: Command Factory”

  1. Phil Steel Says:

    Hi Ed,

    Great post. Would you be able to email the sample app? My place of work are currently blocking the download.

    Many thanks,
    Phil


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: