Task Commands revisited

Posted on Feb 23, 2012 in and tagged , , , ,

Half a year ago I blogged about using TPL with MVVM in a test-friendly way. My solution turned out to be pretty handy, though it was far from being perfect. In this post I will describe what was wrong with the initial implementation and can we slightly improve it.

Looking at that solution right now, I wonder why did I decide to use event async pattern (providing the ExecuteCompleted event) in the first place. The intention was to notify the caller about completion of the asynchronous operation. That is what System.Threading.Task is used for this days, isn’t it? So the obvious solution is to expose the ExecuteAsync() method returning the Task instance on the command class. Here is the source of the updated AsyncRelayCommand:

public class AsyncRelayCommand<T> : ICommand {
    private readonly RelayCommand<T> _internalCommand;
    private readonly Func<T, Task> _executeMethod;
 
    public event EventHandler CanExecuteChanged
    {
        add { _internalCommand.CanExecuteChanged += value; }
        remove { _internalCommand.CanExecuteChanged -= value; }
    }
 
    public AsyncRelayCommand(Func<T, Task> executeMethod, Predicate<T> canExecuteMethod)
    {
        if (executeMethod == null)
        {
            throw new ArgumentNullException("executeMethod");
        }
 
        _executeMethod = executeMethod;
        _internalCommand = new RelayCommand<T>(_ => { }, canExecuteMethod);
    }
 
    public AsyncRelayCommand(Func<T, Task> executeMethod)
        : this(executeMethod, _ => true) { }
 
    void ICommand.Execute(object parameter)
    {
        if (parameter is T)
        {
            ExecuteAsync((T)parameter);
        }
 
        else throw new ArgumentException("Parameter should be of type " + typeof(T));
    }
 
    public Task ExecuteAsync(T parameter)
    {
        return _executeMethod(parameter);
    }
 
    public bool CanExecute(object parameter)
    {
        return _internalCommand.CanExecute((T)parameter);
    }
 
    public void RaiseCanExecuteChanged()
    {
        _internalCommand.RaiseCanExecuteChanged();
    }
}

The code is pretty straightforward, here are the key points:

  • Create an inner command that responds to CanExecute, RaiseCanExecute calls and handles subscriptions to CanExecuteChanged event (optional, since I am using MVVM Light with most of my projects, that’s an acceptable solution for me. However, you may easily implement your own commanding logic).
  • Introduce new ExecuteAsync method that returns Task instance.
  • Implement ICommand.Execute explicitly (I find it more consistent not to have Execute method in the AsyncRelayCommand class).

Side note: as I mentioned in the beginning, I find this command extension rather useful. It was successfully used in 5 own projects (both WP7 and WPF), and I hope you enjoy it too.

As usual, the source code is available at bitbucket (TaskCommands.v2.zip).

MVVM + TPL + Unit tests

Posted on Sep 27, 2011 in and tagged ,

UPD: This implementation didn’t work as well as expected, please read the follow-up article.

Recently I’ve faced an issue with writing unit tests for view model commands that use Task Parallel Library for asynchronous operations. Searching over the web was not really helpful, so I spent some time designing the approach to handle such cases.

The most common way to start tasks with TPL is by using one of the static Task.Factory.StartNew(…) methods. If you are mockist TDD guy, this should already raise an alert in your head. Static members are not test-friendly and do not allow you to inject mock dependencies into your module. One may say that using tasks is just an implementation details and should not be concerned when testing the behavior. I would agree if we were speaking about a regular async method that allows you to perform some action when its execution completes (in a form of callback or event, doesn’t really matter).

That simply doesn’t work for me because the asynchrony is used inside the command handler, so there is no way to specify the continuation outside of the view model.

My first (and probably the bad one) idea was to create a service for running the tasks. Then it would be easy to mock it and run tasks synchronously. Hopefully, I rejected this solution – creating another dependency just didn’t sound right.

I decided to create a special ICommand implementation instead that would notify me when the execution completes. This should do the trick because you can always use the thread sync primitives in the test environment to wait on the asynchronous task.

For simplicity’s sake I just created the wrapper around RelayCommand from MVVM Light Toolkit (you could use your favorite library or implement the command from scratch yourself).

public class AsyncDelegateCommand: ICommand
{
    private readonly RelayCommand _innerCommand;

    public event EventHandler ExecuteCompleted;

    public event EventHandler CanExecuteChanged
    {
        add { _innerCommand.CanExecuteChanged += value; }
        remove { _innerCommand.CanExecuteChanged -= value; }
    }

    public AsyncDelegateCommand(
        Action<AsyncDelegateCommand> executeMethod,
        Func<bool> canExecuteMethod)
    {
        _innerCommand = new RelayCommand(
            () => executeMethod(this),
            canExecuteMethod);
    }

    public void Execute(object parameter)
    {
        _innerCommand.Execute(null);
    }

    public bool CanExecute(object parameter)
    {
        return _innerCommand.CanExecute(null);
    }

    public void NotifyCompleted()
    {
        var handler = ExecuteCompleted;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

Sample application

The test harness application is fairly simple. The single button starts a ‘long-running’ asynchronous task. The button is disabled while the task is running.

public class MainViewModel : ViewModelBase
{
    private bool _isRunning;

    public bool IsRunning
    {
        get { return _isRunning; }
        set
        {
            if (_isRunning != value)
            {
                _isRunning = value;
                RaisePropertyChanged("IsRunning");
            }
        }
    }

    public AsyncDelegateCommand StartLongOperationCommand 
    { 
        get; 
        private set; 
    }

    public MainViewModel()
    {
        StartLongOperationCommand =
            new AsyncDelegateCommand(OnStartLongOperation,
                () => true);
    }

    private void OnStartLongOperation(AsyncDelegateCommand command)
    {
        IsRunning = true;

        Task.Factory
            .StartNew(() => Thread.Sleep(5000))
            .ContinueWith(task =>
            {
                // update UI

                IsRunning = false;
                command.NotifyCompleted();
            }, TaskScheduler.FromCurrentSynchronizationContext());
    }
}

The command handler starts the main task and specifies its continuation that updates the UI properties and notifies when the command is completed. Note that I used the UI task scheduler for the continuation. In this particular case it doesn’t make much sense because WPF automatically dispatches INotifyPropertyChanged events on the UI thread, but our ‘update UI’ logic could be more sophisticated (i.e. ObservableCollection modifications).

Unit Tests

[TestClass]
public class MainViewModelTests
{
    [TestMethod]
    public void CommandShouldNotifyAboutCompletion()
    {
        var context = new SynchronizationContext();
        SynchronizationContext.SetSynchronizationContext(context);
            
        bool notified = false;

        var sync = new ManualResetEvent(false);

        var target = GetTarget();

        target.StartLongOperationCommand.ExecuteCompleted += (s, e) =>
        {
            notified = true;
            sync.Set();
        };

        target.StartLongOperationCommand.Execute(null);
        sync.WaitOne();

        Assert.IsTrue(notified);
    }

    private MainViewModel GetTarget()
    {
        return new MainViewModel();
    }
}

Points of interest:

  • Using ManualResetEvent as a thread synchronization primitive. The main test thread awaits until the sync is set to signaled state on the delegate handler completion.
  • Setting current SynchronizationContext value. UI update continuation task is scheduled on the TaskScheduler, acquired from the current synchronization context. When TaskScheduler.FromCurrentSynchronizationContext is called in the test environment, it throws an exception by default (TaskScheduler.Current and TaskScheduler.Default are both set to null). So we explicitly create and set a new task scheduler.

Download sources (TaskCommands.zip)

Building advanced MVVM commands, Part 1

Posted on Nov 24, 2010 in and tagged , ,

If you follow the MVVM pattern while developing your WPF/Silverlight applications, then you are probably familiar with DelegateCommand (or RelayCommand, as it is called sometimes) model. In brief: it is an implementation of WPF/Silverlight ICommand that allows you to specify what the command should do by passing some delegate that performs execution logic (instead of using CommandBindings). Pretty simple, but powerful pattern.

Dealing with MVVM a lot, I’ve build my own implementation of this pattern that lets you simplify its usage.

Here are some common features, that you have to handle on your own by using classic DelegateCommand:

  • Support for asynchronous execution (usually solved by generating additional code in ViewModel that handles async calls and free/busy indicator).
  • Different command states (Free/Busy/Failed with exception) + UI reactions for those states.
  • Support for execution cancellation and progress tracking (required for asynchronous commands)

Before we start, I offer you to imagine a common command execution timeline. In my opinion it looks like:

  1. Initialize some data (generally, UI settings – clear collections, set some indicators,…)
  2. Perform main execution logic (can be synchronous or asynchronous)
  3. Perform some actions after execution (update UI based on execution result)

And don’t forget about exception handling and correct cross-thread calls for asynchronous commands (all UI changes have to be performed through Dispatcher).

Let’s start with a little helper class, that I called PropertyChangedNotifier. It’s just a wrapper around IPropertyChangedNotifier that has OnPropertyChanged(string propertyName) method. This method raises underlying IPropertyChangedNotifier.PropertyChanged event. Also this class has VerifyPropertyName method that verifies if specified string corresponds to the actual property (this method is marked with [Conditional(“DEBUG”)] attribute and is only used while debugging your applications to find out possible bugs with invalid property names)

public abstract class PropertyChangedNotifier : INotifyPropertyChanged
{
    protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        VerifyPropertyName(propertyName);

        var handler = PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }

    [Conditional("DEBUG")]
    [DebuggerStepThrough]
    private void VerifyPropertyName(string propertyName)
    {
        if (String.IsNullOrEmpty(propertyName))
        {
            return;
        }

        if (TypeDescriptor.GetProperties(this)[propertyName] == null)
        {
            string msg = "Invalid property name: " + propertyName;
            if (ThrowOnInvalidPropertyName)
            {
                throw new Exception(msg);
            }
            Debug.Fail(msg);
        }
    }
}

Let’s start our DelegateCommand with this classic imlementation:

public sealed class DelegateCommand<T>: PropertyChangedNotifier, ICommand where T: class
{
    public Action<DelegateCommand<T>, T> ExecuteAction
    {
        get;
        set;
    }

    public Predicate<T> CanExecutePredicate
    {
        get;
        set;
    }

    public DelegateCommand(Action<DelegateCommand<T>, T> execute, Predicate<T> canExecute)
    {
        ExecuteAction = execute;
        CanExecutePredicate = canExecute;
    }

    public void Execute(object parameter)
    {
        //blank
    }

    public bool CanExecute(object parameter)
    {
        //blank
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}

As I’ve mentioned, we may need to execute this command asynchronously, so I added property IsAsync that lets you specify whether the call will be asynchronous or not. Also as have been discussed earlier, we need delegates for pre-execute, post-execute and error actions.

public Action<T> PreExecute
{
    get;
    set;
}

public event Action<DelegateCommand<T>> Executed;

public Action<Exception> OnException
{
    get;
    set;
}

public bool IsAsync
{
    get;
    set;
}

public bool DisableOnExecution
{
    get;
    set;
}

The last property, DisableOnExecution, tells command to report False to CanExecute calls when it is executed asynchronously.

Remember the command state I’ve told about? Create an enum named CommandState

public enum CommandState
{
    Succeeded,
    Failed,
    IsExecuting
}

and add State property of type CommandState to DelegateCommand.

private CommandState _state;
public CommandState State
{
    get { return _state; }
    set
    {
        if (_state == value)
        {
            return;
        }

        _state = value;

        //if command was executed asynchronously, there may be some issues with correct CanExecute checks,
        //so we force CommandManager to perform that check.
        lock (this)
        {
            if (IsAsync && DisableOnExecution)
            {
                InvokeOnUIThread(CommandManager.InvalidateRequerySuggested);
            }
        }

        OnPropertyChanged("State");
    }
}

This one is a bit tricky. For now, there are some issues with WPF that prevent CanExecute checks when command is executed asynchronously. So when async execution is completed, we tell CommandManager to update all the bindings and re-evaluate CanExecute by calling CommandManager.InvalidateRequerySuggested. Note that is has to be called on UI thread. InvokeOnUIThread adds specified action to the UI dispatcher queue.


public void InvokeOnUIThread(Action action) { Dispatcher.Invoke(action); }

Here Dispatcher is a local variable that is initialized in the constructor.

#if SILVERLIGHT
    Dispatcher = Deployment.Current.Dispatcher;
#else
    Dispatcher = Dispatcher.CurrentDispatcher;
#endif

And if we speak about async calls, let’s add a method that will invoke specified delegate asynchronously:

private static void InvokeAsync(Action task, AsyncCallback executed)
{
    task.BeginInvoke(executed, null);
}

private static void InvokeAsync(Action task)
{
    InvokeAsync(task, x => { });
}

Also you may want to store some exception information if the command execution failed.

private Exception _commandException;
public Exception CommandException
{
    get { return _commandException; }
    set
    {
        if (_commandException == value)
        {
            return;
        }

        _commandException = value;
        OnPropertyChanged("CommandException");
    }
}

Command cancellation? Yes, add IsCancellationPending property. With all this things set up, we are ready to implement Execute and CanExecute methods.

public void Execute(object parameter = null)
{
    var typedParameter = parameter as T;

    Action action = () =>
    {
        try
        {
            CallExecute(typedParameter);
            if (State != CommandState.Failed)
            {
                State = CommandState.Succeeded;
            }
        }
        catch (Exception ex)
        {
            State = CommandState.Failed;
            CommandException = ex;
            CallOnException(ex);
        }
    };

    IsCancellationPending = false;
    CommandException = null;
    State = CommandState.IsExecuting;

    CallPreExecute(typedParameter);

    if (IsAsync)
    {
        var handler = Executed;
        if (handler == null)
        {
            InvokeAsync(action);
        }
        else
        {
            InvokeAsync(action, x => handler(this));
        }
    }
    else
    {
        action();
        CallExecuted();
    }
}

public bool CanExecute(object parameter)
{
    if (CanExecutePredicate != null)
    {
        try
        {
            return !GetIsBusy() && CanExecutePredicate(parameter as T);
        }
        catch
        {
            return false;
        }
    }
    return !GetIsBusy();
}

Methods that are named like CallXXX are just wrappers around corresponding delegates that check if they can be called.

private void CallPreExecute(T arg)
{
    if (PreExecute != null)
    {
        PreExecute(arg);
    }
}

private void CallExecute(T arg)
{
    if (ExecuteAction != null)
    {
        ExecuteAction(this, arg);
    }
}

private void CallExecuted()
{
    var handler = Executed;
    if (handler != null)
    {
        handler(this);
    }
}

private void CallOnException(Exception ex)
{
    if (OnException != null)
    {
        InvokeOnUIThread(() => OnException(ex));
    }
}

GetIsBusy method is pretty simple.

private bool GetIsBusy()
{
    return DisableOnExecution && (State == CommandState.IsExecuting);
}

Note that Execute method can perform both synchronous and asynchronous calls based on IsAsync value. Pre-execution, post-execution and error handling delegates are called on UI thread, so when you use the command, you don’t have to think about.

Building test application

It will be pretty simple. User selects a directory, application lists all the files in this directory and its sub-directories. I’ll start with FileModel class that will represent one list entry

public class FileModel
{
    public String Name
    {
        get;
        set;
    }

    public String Extension
    {
        get;
        set;
    }

    public String Size
    {
        get;
        set;
    }

    public String FullPath
    {
        get;
        set;
    }
}

Next to the ViewModel. It will have Files property (the collection of FileModel) and LoadFilesCommand (implemented as our DelegateCommand)

public sealed class MainWindowViewModel: PropertyChangedNotifier
{
    public MainWindowViewModel()
    {
        Files = new ObservableCollection();
    }
        
    public ObservableCollection Files
    {
        get;
        private set;
    }

    private DelegateCommand _loadFilesCommand;
    public DelegateCommand LoadFilesCommand
    {
        get
        {
            return _loadFilesCommand ?? (_loadFilesCommand = new DelegateCommand(LoadFiles)
            {
                DisableOnExecution = true,
                IsAsync = true
            });
        }
    }

    private void LoadFiles(DelegateCommand cmd, String loadFrom)
    {
        cmd.InvokeOnUIThread(() => Files.Clear());

        Action addFile = file =>
        {
            var model = new FileModel
            {
                Name = Path.GetFileNameWithoutExtension(file),
                FullPath = Path.GetFullPath(file),
                Extension = Path.GetExtension(file),
                Size = GetFileSize(file)
            };
            cmd.InvokeOnUIThread(() => Files.Add(model));
        };

        Action fileLoader = null;
        fileLoader = path =>
        {
            if (cmd.IsCancellationPending)
            {
                return;
            }

            foreach (var file in Directory.GetFiles(path))
            {
                addFile(file);
            }

            foreach (var dir in Directory.GetDirectories(path))
            {
                if (cmd.IsCancellationPending)
                {
                    return;
                }

                try
                {
                    fileLoader(dir);
                }
                catch {}
            }
        };

        fileLoader(loadFrom);
    }

    private static String GetFileSize(String fileName)
    {
        try
        {
            using (var stream = File.OpenRead(fileName))
            {
                return (stream.Length/1024).ToString();
            }
        }
        catch
        {
            return "?";
        }
    }
}

Some comments:

  • We use recursive lambda-function to get all the files in the specified folder.
  • At each loop step we have to check if the user decided to cancel operation.
  • Empty catch are blocks are not good! I used them only to keep things simple. Normally you will have to log all the errors.
  • All actions that change UI state must be performed on UI thread (I use cmd.InvokeOnUIThread(…))
  • Pre-execute, post-execute and error handling are not covered in this sample. I will show how they can be used in the next part.

The application window markup

private void StopButton_Click(object sender, RoutedEventArgs e)
{
    (DataContext as MainWindowViewModel).LoadFilesCommand.IsCancellationPending = true;
}

Event handler in the code-behind file (we will get rid of this in the following parts, so that cancellation will be available from markup)

private void StopButton_Click(object sender, RoutedEventArgs e)
{
    (DataContext as MainWindowViewModel).LoadFilesCommand.IsCancellationPending = true;
}

Run the application. Enter any path in the text box and click Start button. It will be disabled and application will start to fill the list with file information. Clicking Stop will cancel this operation.

Sample application that uses async commands

That’s all for now. With this implementation we can keep ViewModels clean and perform async operations practically the same way that we would perform the usual ones.

Download sources

In the next parts I will show how the progress tracking can be added, how we can improve command initialization with fluent extensions and how it all can be combined with visual states via DataTemplates techniques I’ve described earlier. Good luck =)