Labels

Wednesday, October 13, 2010

Silverlight Threading

Threading in Silverlight is no more new than the regular Threading works.
However there are two new things to know here.

·         DispatcherTimer
·         BackgroundWorker

DispatcherTimer

Let’s understand the quick need of Dispatcher by below example.

Much like .NET client applications (e.g. WPF & WinForms applications), Silverlight supports a Single-Threaded Apartment Model. In this model, a single thread runs your entire application and owns all the objects that represent user-interface elements. The thread that creates them  owns them, and other threads can’t interact with them directly.
If this rule is violated – as shown in below example, by trying to access a user-interface object from a background thread–you’re certain  to cause an immediate exception, a lock-up, or a subtler problem.


Problem

protected void Unnamed1_Click(object sender, RoutedEventArgs e)
{       
   ThreadStart thst = new ThreadStart(ThreadRole);
   Thread th = new Thread(thst);
   th.Start();      
}


private void ThreadRole()
{
  try
  {
    Thread.Sleep(2000);
    Label1.Text = "Done"; // Does Not Affects
  }
  catch (Exception ex)
  {
    Throw ex// Invalid cross-thread access Exception
  }
}



This is where Dispatcher comes in picture. The dispatcher owns the main application thread and thus able to perform the above violated work.


Solution using Dispatacher

private void ThreadRole()
{
  Thread.Sleep(2000);
  this.Dispatcher.BeginInvoke(delegate()
  {
    Label1.Text = "Done"// Makes Affect
  });
}


The DispatcherTimer doesn’t offer true multithreaded execution. Instead, it triggers a periodic Tick event on the main application thread.
This advantage of having the tick event always executing on the main application thread, side steps synchronization problems and the other headaches. Refer above example.

This event interrupts whatever else is taking place in your application, giving you a chance to perform some work. I.e It halts/locks the main application / user interface.
This behavior on one hand side steps synchronization problems, but on the other hand it also introduces a number of limitations. I.e. This is fine if you need to  frequently perform small amounts of work,  but if it is a time-consuming task, then the user interface locks up until it’s finished. Thus, the DispatcherTimer doesn’t help you make a user interface more responsive.

So the case where time-consuming task is required, you need the real multithreading.

Here are examples of some small amounts of work that can be handled thru DispatcherTimer.
·         For example, it’s a great way to periodically check a web service for new data.  As we know all web service calls are asynchronous and are carried out on a background thread. Thus, we can use the   DispatcherTimer to just launch the web service call asynchronously and come back. This will enable the time-consuming download to take place on a background thread.

The BackgroundWorker (System.ComponentModel.BackgroundWorker)

The BackgroundWorker component, which was first introduced with .NET 2.0 to simplify threading considerations in WinForms applications.
Fortunately, the  BackgroundWorker is equally at home in Silverlight.

The BackgroundWorker component is one of the simplest and safest approaches to multithreading.
This gives you a nearly foolproof way to run a time-consuming task on a separate thread.
Silverlight recommends whenever possible, it’s better to use the straightforward BackgroundWorker component than the lower-level Thread class.
Reason being –

·         It supports event-based model to notify client application about Progress/Cancellation.
·         Secondly, to achieve this event-based model, it uses the dispatcher behind the scenes. Thus abstracts away the marshalling issues with an event-based model. (As discussed above).

The BackgroundWorker’s core events are DoWork, ProgressChanged, and RunWorkerCompleted.


Solution using Dispatacher

private BackgroundWorker backgroundWorker = new BackgroundWorker();
public BackgroundWorkerTest()
{
 InitializeComponent();
 backgroundWorker.WorkerReportsProgress = true;
 backgroundWorker.WorkerSupportsCancellation = true;

 backgroundWorker.DoWork += backgroundWorker_DoWork;
 backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
 backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
}


Note
·         BackgroundWorker is perfect if you have a single asynchronous task that runs in the background from start to finish (with optional support for progress reporting and cancellation).
·         If you have something else in mind—for example, an asynchronous task that runs throughout the entire life of your application or an asynchronous task that communicates with your application while it does its work—you must design a customized solution that uses the threading features you’ve already seen.


Hope this helps.

Regards,
Arun Manglick

No comments:

Post a Comment