Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Asynchronous WPF Command

0.00/5 (No votes)
27 Jan 2012 1  
Asynchronous WPF command

The ICommand interface provides a nice way of binding WPF buttons to methods in a view model. If those methods use any amount of time, though, you'll want to run them in a background thread.

This implementation of ICommand is an easily-extendable way to run methods in an async manner when a button is clicked. The base class creates a BackgroundWorker that runs a proxy for the Execute method. All you have to do is override OnExecute.

The...

C#
BeforeExecute

...method allows you to run operations on the UI thread immediately before the BackgroundWorker does its async operation.

The...

C#
AfterExecute

...method allows you to run operations after the BackgroundWorker completes its work. It also provides the Exception object (if one was thrown) that was thrown in the background thread.

/// <summary>
/// Implementation of <c>ICommand</c> that allows for asynchronous operation.
/// </summary>
public class AsyncCommandBase : ICommand
{
    /// <summary>
    /// Raises the <c>CanExecuteChanged</c> event for the command.
    /// </summary>
    /// <remarks>This method should be invoked whenever the 
    /// returned value of <c>CanExecute</c> changes.</remarks>
    protected void RaiseCanExecuteChanged()
    {
        if (CanExecuteChanged != null) CanExecuteChanged(this, new EventArgs());
    }
 
    /// <summary>
    /// When overridden in a derived class, performs operations in the UI thread
    /// before beginning the background operation.
    /// </summary>
    /// <param name="parameter">The parameter passed to the 
    /// <c>Execute</c> method of the command.</param>
    protected virtual void BeforeExecute(object parameter) { }
 
    /// <summary>
    /// When overridden in a derived class, performs operations in a background
    /// thread when the <c>Execute</c> method is invoked.
    /// </summary>
    /// <param name="parameter">The parameter passed to the 
    /// <c>Execute</c> method of the command.</param>
    protected virtual void OnExecute(object parameter) { }
 
    /// <summary>
    /// When overridden in a derived class, performs operations when the
    /// background execution has completed.
    /// </summary>
    /// <param name="parameter">The parameter passed to the 
    /// <c>Execute</c> method of the command.</param>
    /// <param name="error">The error object that was thrown 
    /// during the background operation, or null if no error was thrown.</param>
    protected virtual void AfterExecute(object parameter, Exception error) { }
 
    /// <summary>
    /// Occurs when changes occur that affect whether or not the command should execute.
    /// </summary>
    public event EventHandler CanExecuteChanged;
 
 
    /// <summary>
    /// When overridden in a derived class, defines the method that 
    /// determines whether the command can execute in its
    /// current state.
    /// </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>
    /// <returns>True if this command can be executed; 
    /// otherwise, false.</returns>
    public virtual bool CanExecute(object parameter)
    {
        return true;
    }
 
    /// <summary>
    /// Runs the command method in a background thread.
    /// </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>
    public void Execute(object parameter)
    {
        BeforeExecute(parameter);
 
        var bgw = new BackgroundWorker();
 
        bgw.DoWork += (s, e) =>
        {
            OnExecute(parameter);
        };
        bgw.RunWorkerCompleted += (s, e) =>
        {
            AfterExecute(parameter, e.Error);
        };
        bgw.RunWorkerAsync();
    }
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here