Asynchronous Commands in Metro, WPF & Silverlight

I’ve seen quite a few examples demonstrating the new async/await language features (C# 5 & VB next) with button click events;

private async void button1_Click(object sender, RoutedEventArgs e)
{
    string url = "http://reedcopsey.com";
    string content = await new WebClient().DownloadStringTaskAsync(url);
    this.textBox1.Text = string.Format("Page {0} supports XHTML 1.0: {1}",
      url, content.Contains("XHTML 1.0"));
}

If you are using an architectural pattern like MVVM it’s unlikely that you’re writing code like this. In WPF, Silverlight & Metro you can bind buttons directly to an object implementing the ICommand interface.

// WPF ICommand interface
public interface ICommand
{
    /// <summary>
    /// Defines the method to be called when the command is invoked.
    /// </summary>
    /// <param name="parameter">Data used by the command.
    /// If the command does not require data to be passed, this object can be set to null.</param>
    void Execute(object parameter);

    /// <summary>
    /// Defines the method that determines whether the command can execute in its current state.
    /// </summary>
    /// 
    /// <returns>
    /// true if this command can be executed; otherwise, false.
    /// </returns>
    /// <param name="parameter">Data used by the command.
    /// If the command does not require data to be passed, this object can be set to null.</param>
    bool CanExecute(object parameter);

    /// <summary>
    /// Occurs when changes occur that affect whether or not the command should execute.
    /// </summary>
    event EventHandler CanExecuteChanged;
}

The nice thing about commands vs. a simple click event is that they encapsulate the logic informing the button wether or not it can be executed. This is particularly useful when we start talking about asynchronous operations as we might like to disable the button while the asynchronous request is in flight.

Example

    public bool CanExecute(object parameter)
    {
        return !isExecuting;
    }

    public async void Execute(object parameter)
    {
        isExecuting = true;
        OnCanExecuteChanged();
        try
        {
            // await some asynchronous operation
        }
        finally
        {
            isExecuting = false;
            OnCanExecuteChanged();
        }
    }

What About Errors?

Note that commands are generally executed by the UI frameworks message loop, meaning that any unhandled exceptions will be posted onto the relevant synchronisation context.

AsyncCommand

This pattern is easily captured in a reusable object that we can use to build all our asynchronous commands.

    // a reusable asynchronous command
    public class AsyncCommand : ICommand
    {
        private readonly Func<Task> execute;
        private readonly Func<bool> canExecute;
        private bool isExecuting;

        public AsyncCommand(Func<Task> execute) : this(execute, () => true) { }

        public AsyncCommand(Func<Task> execute, Func<bool> canExecute)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            // if the command is not executing, execute the users' can execute logic
            return !isExecuting && canExecute();
        }

        public event EventHandler CanExecuteChanged;

        public async void Execute(object parameter)
        {
            // tell the button that we're now executing...
            isExecuting = true;
            OnCanExecuteChanged();
            try
            {
                // execute user code
                await execute();
            }
            finally
            {
                // tell the button we're done
                isExecuting = false;
                OnCanExecuteChanged();
            }
        }

        protected virtual void OnCanExecuteChanged()
        {
            if (CanExecuteChanged != null) CanExecuteChanged(this, new EventArgs());
        }
    }

Usage

In your view model you can now create asynchronous commands like this;

// example command, simulate an operation that takes 2 seconds.
new AsyncCommand(() => TaskEx.Delay(2000));

// example command, with some custom can execute logic
new AsyncCommand(() => TaskEx.Delay(2000), () => IsValidInput());

 

Memory Leaks

A word of warning… If your command object’s lifetime extends beyond that of the UI element (Button) that is subscribing to the CanExecuted event you should implement a weak event pattern in here. I think that is outside the scope of this article. I’ll follow up shortly.

In Conclusion

This is a great example of why async void methods are required in C#. Commands are like a bridge between synchronous UI elements like buttons and your view models asynchronous operations like web requests. Enjoy!

Follow

Get every new post delivered to your Inbox.