Threading as Command in MVVM

So far in previous posts (1, 2) I have done some processing work in the background using first BackgroundWorker class and then refine it using the new Task of .NET4.

One of the main purposes of these posts is to learn more about threading and processing stuff in the background.

This time I am trying to wrap this in a reusable manner with MVVM. The following code is greatly inspired by this post: Asynchronous WPF Commands over at SharpFellows.

So, what I wanted to do was to create a way for my application to be able to process long running stuff asynchronous so that my GUI won’t freeze while waiting.

In a MVVM fashion most calls to such long running stuff is initiated via a binding to ICommand

public interface ICommand
{
    event EventHandler CanExecuteChanged;
    bool CanExecute(object parameter);
    void Execute(object parameter);
}

An implementation usually takes two delegates as inputs which are then invoked in CanExecute and Execute. Something like:

...
public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod=null)
...

In this case my implementation looks like the following:

public TCommandViewModel(IInvoker commandInvoker, Func<bool> canExecuteMethod = null)
{
    if (canExecuteMethod != null)
        this.canExecuteMethod = canExecuteMethod;

    invoker = commandInvoker;
}

and IInvoker looks like this:

public interface IInvoker
{
    void QueueWork();
    event EventHandler WorkFinished;
}

The interesting part of TCommandViewModel looks like this:

public void Execute()
{
    string tempHeader = Header;
    invoker.WorkFinished += (s, e) =>
    {
        IsBusy = false;
        Header = tempHeader;
    };
    IsBusy = true;
    Header = BusyHeader;
    invoker.QueueWork();
}

Basically whats going on is that the execution of “Execute” delegate is handed of to IInvoker, which also reports via the event WorkFinished when execution is completed.

I have made two implementations of IInvoker. First one is the “simple”, the synchronous execution:

public class SyncInvoker : IInvoker
{
    private Action work;

    public SyncInvoker(Action workDelegate)
    {
        work = workDelegate;
        WorkFinished = delegate { };
    }

    public void QueueWork()
    {
        work();
        WorkFinished(this, EventArgs.Empty);
    }

    public event EventHandler WorkFinished;
}

and the second one, the async one, where finally some interesting stuff happens:

public class AsyncInvoker : IInvoker
{
    private Action work;

    public AsyncInvoker(Action workDelegate)
    {
        work = workDelegate;
        WorkFinished = delegate { };
    }
       
    public void QueueWork()
    {
        Task.Factory.StartNew(work)
            .ContinueWith(y => WorkFinished(this, EventArgs.Empty));
    }

    public event EventHandler WorkFinished;
}

So, what happens when QueueWork() is called is that a new Task is created and started via Task.Factory. When finished WorkFinished event is fired.

A command can now be constructed in the viewmodel like this:

public ICommand FetchTweetsCommand
{
    get
    {
        IInvoker invoker = new AsyncInvoker(() =>
            {
                IEnumerable<TwitterStatus> fetchedTweets = LoadTweetsOnPublicTimeLine();
                LoadList(fetchedTweets);
            });

        return new TCommandViewModel(invoker)
        {
            Header = "Load tweets",
            BusyHeader = "Loading..."
        };
    }
}

The property above returs property of type ICommand which is bound to a button in the view. The IInvoker gets a delegate (lambda-style in this case) which loads tweets from the public timeline (takes approx 5 seconds) and loads these in to a bound ObservableCollection.

A nice thing about this is that it’s very easy to call a method/service async only when needed. Replacing the above code with

...
        IInvoker invoker = new SyncInvoker(() =>
            {
                IEnumerable<TwitterStatus> fetchedTweets = LoadTweetsOnPublicTimeLine();
                LoadList(fetchedTweets);
            });
 ...

Will create a command which invokes its execute delegate synchronously. Depending on situation I can easily switch between sync and async way to invoke ICommand’s execute delegate.

Ironically enough, this was written the same day as Microsoft announced the future of C# at PDC. With the new “async” and “await” (or whatever they will be called) keywords, this would probably be much simpler to write.

There’s a bunch of things which I have not included in this. Error handling and cancellation are two obvious thing that comes to mind. Maybe in a future post :-)

Leave a Reply

You must be logged in to post a comment.