Cover

For Now, Don't Use SynchronizationContext in Silverlight 2 or 3

April 12, 2009
No Comments.

Url: http://wilderminds.blob.core.windows.net/downloads/oddsynccontext.zip

In Silverlight (and WPF before) I became enamoured with the Dispatcher for marshaling data back to the UI thread. It works, its simple (and throw in lambda’s in C# and its super easy). But I’ve been trying to be a good citizen lately. It seems that many people are using SynchronizationContext to do this instead. The SynchronizationContext class is available in Silverlight, WPF and in Windows Forms so it felt like its what I should be using so that code I write would be portable.

So in a recent project I was writing for an article, I was using it but it simply failed and had me perplexed.  Maybe I was using it wrong?  Maybe it didn’t work with lambda expressions?  Maybe I needed to reboot my machine?  It just felt wierd.

As is my style, I took the problem out of the project and built a quick tester so I could see if I could replicate the problem (something I advocate heavily).

So I wrote a little tester (you can get it from the link above if you’re interested) to see how the Dispatcher and SynchronizationContext worked in different situations. In my tester, I tested both the Dispatcher and the SynchronizationContext object from the UI thread, from a ThreadPool thread, a BackgroundWorker thread and from a custom built Thread.

In the Dispatcher examples, I am getting at the Dispatcher through the Deployment.Current object which is how you should do it since UI elements with Dispatcher won’t like being called from a separate thread.  For example, using a ThreadPool thread, I call the Dispatcher (like so:

ThreadPool.QueueUserWorkItem(new WaitCallback(
  o =>
  {
    try
    {
      Deployment.Current.Dispatcher.BeginInvoke(
        () => results.Text = "Pooled Dispatcher Worked");
    }
    catch (Exception ex)
    {
      Debug.WriteLine("Pooled Dispatcher - Error occurred: {0}", ex);
    }
  }));

And the SynchronizationContext like so:

ThreadPool.QueueUserWorkItem(new WaitCallback(
  o =>
  {
    try
    {
      SynchronizationContext.Current.Post(
        new SendOrPostCallback(
          ignore => results.Text = "Pooled Synchronization Worked"), null);
    }
    catch (Exception ex)
    {
      Debug.WriteLine("Pooled SyncContext - Error occurred: {0}", ex);
    }
  }));

I found odd behavior. The SynchronizationContext.Current (the property that you use to do the marshaling) was null unless you were on the UI thread.  Wait, did I just type that?  The very property that you need to use when you’re *not* on the UI thread isn’t available unless you’re on the UI thread?  Yup, that appears to be the situation.

I also tested this against the current Silverlight 3 build and its behaves exactly the same way.

So for now, (unless I just missed something big) I suggest sticking with Dispatcher we find out why this is happening.

UPDATE: As several have pointed out, you need to cache the SynchronizationContext.Current and pass it along to the non-UI thread. It is working as designed, but for Silverlight I am sticking to the Dispatcher as it has fewer moving parts.