Threading and Marshaling in Silverlight 2.0

Quick: can you spot what’s wrong with this code?

Thread thread = new Thread(new ThreadStart(RunClock));

thread.Start();

 

private void RunClock()

{

    while (true)

    {

        Clock.Text = DateTime.Now.ToLongTimeString();

    }

<

p class=”MsoNormal”>} 

The intent is to launch a thread and have that thread run an infinite loop updating a XAML TextBlock object that shows the current time of day. Aside from the questionable design (there are much more efficient ways to keep a time-of-day display up to date), there’s something seriously wrong with this code. In fact, if you run it you’ll find that the time-of-day display never updates at all. And therein lies a story.

I was surprised last year when I saw that the Silverlight 1.1 alpha had a System.Threading namespace complete with all the classes I needed to launch threads, synchronize threads, acquire threads from a thread pool, etc. Silverlight 2.0 Beta 1 contains all these classes and more. I’m still amazed that I can write multithreaded apps that run in a browser, and I’ve been doing a lot of that lately–not because I need to, but just because I can. Silverlight 2.0’s BackgroundWorker class simplifies the process of running tasks on background threads, and DispatchTimer is a handy alternative to empty Storyboards for programmable game timers. But you don’t have to use either of them; you can use Thread.Start, ThreadPool.QueueUserWorkItem, asynchronous delegates, and other mechanisms familiar to .NET developers to relegate tasks to background threads.

There is one nuance to Silverlight threading that you should be aware of, however: controls and other XAML objects can only be updated by the UI thread (the main thread that drives a Silverlight app). The reason the attempt to set the TextBlock’s Text property in the example above fails is that we’re attempting to set it from a background thread. For the sample to work, you need to modify it as follows:

private delegate void UpdateUIDelegate();

 

Thread thread = new Thread(new ThreadStart(RunClock));

thread.Start();

 

private void RunClock()

{

    UpdateUIDelegate action = new UpdateUIDelegate(UpdateUI));

 

    while (true)

    {

        Clock.Dispatcher.BeginInvoke(action);

    }

}

 

private void UpdateUI()

{

    Clock.Text = DateTime.Now.ToLongTimeString();

}

In the corrected code, the background thread marshals the call back to the UI thread by calling UpdateUI through a delegate invoked via the TextBlock object’s Dispatcher property. Dispatcher is inherited from DependencyObject and is therefore present in all UI objects. For old folks like me who used to program Windows, this is analagous to using PostMessage to post a message to another thread. You don’t have to use the Dispatcher property of the object you intend to update; you can use Dispatcher on any UI object to marshal the call to the UI thread.

Programmers who have written multithreaded WPF apps won’t be surprised by any of this because WPF also requires UI objects to be updated by UI threads. And of course there are ways to avoid using Dispatcher altogether. The BackgroundWorker class, for example, fires events on UI threads, so there’s no need to do any marshaling before updating a UI object. But there are times in Silverlight when you simply can’t avoid marshaling from a background thread to a UI thread, and when those circumstances arise, it’s useful to know about Dispatcher.

Stay Informed

Sign up for the latest blogs, events, and insights.

We deliver solutions that accelerate the value of Azure.
Ready to experience the full power of Microsoft Azure?

Atmosera is thrilled to announce that we have been named GitHub AI Partner of the Year.

X