Published: 30 Mar 2011
By: Xianzhong Zhu
Download Sample Code

In this article, I would like to sum up the several multi-threaded programming techniques in Silverlight 4 as comprehensively as possible. And, as usual, I'll try to bring you the related sample code scraps.

Contents [hide]

Introduction

Silverlight is Microsoft's important RIA tool whether in the Web application developing area or in the desktop scenario. In fact, since Silverlight for Windows Phone 7 was born last year, Silverlight has been attracting more and more developers' eyes. As its direct competitor Flash, Silverlight, since its first version, has provided support for multithread based computing. On the whole, the fundamental motive of introducing multithreading in Silverlight is to improve the user experience to solve the user experience of responsiveness, by reducing the congestion of single threaded.

In this article, I would like to sum up the several multi-threaded programming techniques in Silverlight 4 as comprehensively as possible. And, as usual, I'll try to bring you the related sample code scraps.

NOTE

The sample test environments in this article involve:

1. Windows 7;

2. .NET 4.0;

3. Visual Studio 2010 (with Silverlight 4).

Introducing the Thread Class

The Thread class is the first thing you should know in multithreading programming in Silverlight. There are many members defined in the Thread class. However, we are not to enumerate them, but let a concrete example to show you the basic usage of the important ones.

As is seen above, to use the Thread class, we should begin by creating a new Thread object, at which point we supply a delegate to the method to invoke asynchronously. In this case, DoWork is the method performed by a background thread (here the delegate type omitted). Note the ThreadStart delegate can not take parameters, while the ParameterizedThreadStart delegate can be parameterized. Later examples will show the related usage. Second, the IsBackground property specifies whether this is a background thread (for Silverlight, it did not distinguish whether or not it is a background thread). The Start method is used to start the thread, passing an integer to specify the sleeping time (millisecond). Note the Start() method returns immediately, and the related code begins executing asynchronously on a new thread. In fact, we can pass any object to the Start method. Refer to the following definition:

Also note that, the method Join() is used to block the calling thread (in this case the main thread), until the specified thread (in this case thread) is finished. If the specified thread is finished then continue to execute the subsequent statements; if the specified thread runs longer than the specified time, then also continue. The return value specifies, within the specified time, whether or not the specified thread is finished executing.

Now, let's consider the following really interesting thing:

The above code will fail – a running-time UnauthorizedAccessException will be thrown warning "Invalid cross-thread access". This shows the thread isn't allowed to access Silverlight objects. This, in fact, presents a typical case under the multithreading environment. To solve this problem, you are generally suggested to rest upon the System.Windows.Threading.Dispatcher object.

Using System.Windows.Threading.Dispatcher

Before diving into the System.Windows.Threading.Dispatcher object, let's first see how to tackle the above problem.

Run the above code again, you will find the value of the Content property of the Button control is modified successfully. To gain a more modular design style, you can also express the same functionality as below:

As in many other frameworks, threads in Silverlight are also divided into two categories: UI thread and worker thread. Silverlight UI thread is the thread interacting with the user. In the UI thread, there are the UI control classes and the ViewModel classes targeting data binding. And according to the design Silverlight framework, a background worker thread cannot directly access the properties of data objects and controls in the UI thread. But there is no need to worry about this. The threading model in Silverlight has leveraged a secure event based dispatcher model that is similar to EDT (Event Dispatch Thread) in Java Swing, with which we can also easily succeed in data exchange between the UI thread and the background worker thread.

We know that all Silverlight controls inherit from the base DependencyObject class. What deserves noticing is the DependencyObject class not only provides the fundamental dependency property service for Silverlight but also opens a channel for data exchange between the UI thread and the background worker thread. DependencyObject has a very important property – Dispatcher. So, the background thread can call the Dispatcher object of the launcher (mostly is the UI control) to achieve interoperability. The following illustrates a typical schema for operation:

The above () => is a Lambda Expression representing the short form of the delegate method without incoming parameters. If there are incoming parameters we can specify them in the parentheses.

Deployment.Current.Dispatcher

Till now, the preceding samples take place on the premise that the UI controls have been launched. As we've known, ordinarily the Application.Current.RootVisual.Dispatcher property is used to retrieve the System.Windows.Threading.Dispatcher for an application. However, this won't work if performed before the RootVisual has been assigned. To get the Dispatcher for an application before the RootVisual has been assigned, we should resort to the System.Windows.Deployment.Current.Dispatcher object.

And also, in the case of a .dll library, we can use Deployment.Current.Dispatcher to obtain the reference to Dispatcher. For instance, to change the value of the Text property of a Silverlight control in an UI thread, you can use the following code:

BTW, here is a good example using Deployment.Current.Dispatcher for your reference.

About SynchronizationContext

SynchronizationContext seems to be mysterious stuff compared with the preceding things. According to MSDN, it "provides the basic functionality for propagating a synchronization context in various synchronization models." According to my searching results from the Internet, the conclusion should be: the invention of SynchronizationContext aims to simplify the synchronization provided you are sure enough that you are on the UI thread; or else, it will return a null. So, in most cases, you can use Deployment.Current.Dispatcher as a replacement. As for using SynchronizationContext, it is not difficult. For example, you also can achieve the similar operation as above with the synchronization context, as follows.

Note Daniel Vaughan provides a good encapsulation with SynchronizationContext; cute readers can do more related digging.

ThreadPool

In all multithreaded solutions, ThreadPool should be your most commonly used technique. The advantage of using ThreadPool is apparent: 1, it is easy to control as well as powerful, helping to reduce the whole cost concerning multithread coding; 2, in the thread pool a thread will not extinct due to the end of a task, but will continue to perform other tasks, greatly reducing thread creation and destruction overhead. ThreadPool provides an important method - QueueUserWorkItem which can push any processing function into a background thread executed in the queue. And also, its creation is also pretty simple.

In fact, you will find there is not much difference in performing the same task compared with the above approach.

Now, let's look more closely at the usage of ThreadPool. Here we will construct two samples: one still relates to the method QueueUserWorkItem; the other relates to another method RegisterWaitForSingleObject.

First, let's put two TextBlock controls on the sample page ThreadPoolTestPage.xaml:

When clicking the either of the two labels, a related sample process will be launched. Let's continue what happens in the behind code:

For the first method QueueUserWorkItem, we just notice two points. First is the parameter definition.

Listing 1: There are two overloads for the method QueueUserWorkItem

Here the first parameter specifies the method to execute, while the second parameter is used as argument passed to the method. Second, the method executes only when the thread becomes available in the thread pool. As you would image, as part of thread management strategy, there is a certain degree of delay before thread pool creates the thread. This is why we invoke the Thread.Sleep method.

For the second method RegisterWaitForSingleObject, there are some complexities. First, we set up an AutoResetEvent instance, passing in the false parameter. Second, we introduce a helper class RegisteredWaitHandlePacket with which to encapsulate another RegisteredWaitHandle class. There are several parameters for the method RegisterWaitForSingleObject. However, we are not going to dwell upon them since MSDN has given more detailed explanation. And also, we used the delay policy for the second method.

NOTE

Although the ThreadPool provides two methods, SetMinThreads and SetMaxThreads, but not available - calling them will trigger an exception.

About WaitHandle

A wait handle is the essential equipment for multithreaded programming. Since our main interest lies in the Silverlight related multithreading stuff, we are not to delve into WaitHandle, but bring you a typical example to tell how to use it.

Timer

System.Thread.Timer is a multi-threaded timer. It is a simple, lightweight timer that uses callback methods and is served by thread pool threads. Let's look at a related example:

Listing 2: (see the sample page TimerTestPage.xaml)

There are several points deserved noticing here. First, make clear the parameters passed to Timer class: the method MyTimerCallback represents a method to be executed in the thread pool; the second parameter (a string in this case) means data passed to the method MyTimerCallback; the third parameter specifies the amount of time to delay before the method MyTimerCallback is invoked, in milliseconds; the forth one specifies the time interval between invocations of the method MyTimerCallback, in milliseconds. Second, we've used the SynchronizationContext object since the threading context is clear to track. Also note, inside the method MyTimerCallback we called the Post method of it to modify the content in the UI thread. Last, through the method Change of Timer we specify that after the method executes 5 times, change the start time to five minutes and the interval to five milliseconds between method invocations for the timer.

System.Windows.Threading.DispatcherTimer

DispatchTimer first appears in Silverlight (WPF), as a background thread timer. Compared with the original System.Threading.Timer, the difference lies in that DispatchTimer is truly executed independently within a background thread, while the Timer is still executed in the UI thread but every specified time takes over the right to control the UI thread. DispatchTimer is only suitable for scheduled tasks. We can set the waiting break according to factual requirements.

In fact, DispatcherTimer is also an important component to achieve animation except for the StoryBoard component. Of course, we should be careful with the DispatcherTimer to build too many the background threads; otherwise they will result in increasing the CPU scheduling overhead to decrease efficiency.

BackgroundWorker - the Lazy Way

System.ComponentModel.BackgroundWorker was first introduced with .NET 2.0 to simplify the coding process of thread interactions in Windows Forms applications. Now, it can also be used in the Silverlight environment. Behind the scenes, BackgroundWorker uses the Dispatcher component and encapsulates all the multithreading intricateness inside a black box, providing you a most easy-to-use and ready-to-use solution. On the whole, BackgroundWorker is pretty suitable for undertaking a single, asynchronous, and long task that runs in the background.

Peeking result via .NET Reflector

Now, let's first look at the declaration of the BackgroundWorker class using .NET Reflector.

Implied from the names, you will easily image most of the members are commonly used. For brevity, we will no more delve into the related explanations. However, we will construct a concrete example to look at a typical case using BackgroundWorker.

On the whole, BackgroundWorker is suitable to run an operation on a separate thread, especially to run a time-consuming operation on a non-UI thread to prevent from UI stopping response. Above, we used a 'Cancel' button to cancel the thread executing by judging whether the thread allows cancelled (through the property WorkerSupportsCancellation). And then, we invoke the method CancelAsync to suspend the thread. Correspondingly, the method RunWorkerAsync is used to start the thread, passing the possible required parameters. As is seen, the real asynchronous work is done in the method _backgroundWorker_DoWork. At the same time, it reports the progress using the method ReportProgress; a related method _backgroundWorker_ProgressChanged is responsible to render the progress on the UI thread. As soon as the thread terminates or is suspended another related method _backgroundWorker_RunWorkerCompleted will invoked and output the related prompt info.

Summary

In this article, we've summed up the typical ways to incorporate multithreading into a Silverlight application. However, writing a multithreaded Silverlight application is not as easy as covered herein – we've just scratched the surfaces. Hence, before putting multithread programming into your real work, you are highly suggested considering the advice of Microsoft. Frankly speaking, to choose multithreading means in a great degree you have to face up with locking complications and synchronization mechanisms. Whether to introduce multithreading into your Sivlerlight projects or not should depended on your final decision.

<<  Previous Article Continue reading and see our next or previous articles Next Article >>

About Xianzhong Zhu

I'm a college teacher and also a freelance developer and writer from WeiFang China, with more than fourteen years of experience in design, and development of various kinds of products and applications on Windows platform. My expertise is in Visual C++/Basic/C#, SQL Server 2000/2005/2008, PHP+MyS...

This author has published 81 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category


Displaying Notification Messages in a Silverlight Dashboard Application
In this article we will see how we could display a notification message and further a list of notifi...
Air Space Issue in Web Browser Control in Silverlight
Air Space issue is a common issue in Web Browser control in Silverlight and WPF. To explain the issu...
TextBox Row Filter in Telerik's RadGridView in Silverlight
If you have come across the JQGrid features, you might have seen the filter row available as the fir...
Widget Refresh Timer in MVVM in Silverlight
In this article we'll see how to refresh and disable widgets using the Model View View-Model pattern...
Develop a Flexible 2.5D Scene Editor Targeting Silverlight RPG Games - Part 2
In this article, I'm going to introduce to you how to construct such a 2.5D RPG game scene editor th...

You might also be interested in the following related blog posts


Building A Product For Real read more
Silverlight MVP read more
Mixing Silverlight and MS ASP.NET AJAX 3.5 in the same web application. read more
In Response To DNR 476 read more
Building a Silverlight 3 based RIA Image Magagement System (1) read more
Building a Silverlight 3 based RIA Image Management System - 1 read more
Telerik Launches RadControls for Silverlight 3 for Line-of-Business Application Development read more
Provide startup parameters to Silverlight with InitParams read more
Silverlight Twitter Client with authentication read more
OMG, where do I start? read more
Top
 
 
 

Discussion


Subject Author Date
placeholder wonderful Net 205 3/30/2011 9:15 AM

Please login to rate or to leave a comment.