Magically dispatching asynchronous method calls

One of the things I like less about Silverlight is the visibility of its Threading limitations code that has nothing to do with explicit threading. I think that explicitly handling the threads and everything attached is something that you should only need to do when you want to, otherwise it shoud nicely step aside.

The point where threading jumps into your face is when you receive a callback from an asynchronous method call, and after that, need to drive each modification of a UI element through an explicit call of Dispatcher.BeginInvoke. While this is not the end of the world, I strongly dislike it mostly because it makes the code less readable. In addition, since BeginInvoke does of course not wait until the dispatched instruction completes, leads to unnecessarily complex code when several methods need to chained into one.

When reviewing code that uses the WebClient class to download content from an REST service however, it occurred to me that there were no Dispatcher calls in the code. I first thought that was an error, but it turns out that WebClient (and only WebClient, AFAICS) dispatches back to the main thread by itself, yielding a much clearer programming pattern. And I wanted to have the same kind of magic for everything else too.

In fact, it’s very easy; the Dispatcher needs to be called at some point in time, I just tried to shift that point to its earliest possible: the callback method of the asynchronous method. Then that Dispatcher call is packaged nicely as a single method call, and we’ve got:

myServceClient.BeginGetData(
  AsyncUtility.DispatchCallback( ar => DataContext = myServceClient.EndGetData( ar ) )
  , null );

And here’s the AsyncUtility helper class.

using System;
using System.Diagnostics;

namespace GreenIcicle.Silverlight
{
  public class AsyncUtility 
  {
    public static AsyncCallback DispatchCallback( AsyncCallback callback )
    {
      return ( new DispatchedCallback( callback ).Execute );
    }

    private class DispatchedCallback
    {
      private AsyncCallback m_Callback;

      public DispatchedCallback( AsyncCallback callback )
      {
        m_Callback = callback;
      }

      public void Execute( IAsyncResult result )
      {
        System.Windows.Threading.Dispatcher dispatcher = System.Windows.Deployment.Current.Dispatcher;
        dispatcher.BeginInvoke( () => m_Callback( result ) );
      }
    }
  }
}
Advertisements
About

Christian is a software architect/developer. He lives in Germany, reads a lot, and likes cycling.

Tagged with: , , , ,
Posted in Coding

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: