Silverlight Hack

Silverlight & related .NET technologies

About Me

Welcome to Silverlighthack.com.  This is a site where you can find many articles on Silverlight, Windows Phone 7 and .NET related technologies.  

My name is Bart Czernicki.  I have been working with computers since 1988 and have over 12 professional years in the IT field focusing on architecture, technology strategy and product management.  I currently work as a Sr. Software Architect at a large software development company.

Below is the cover of my new book that shows how Silverlight's unique RIA features can be applied to create next-generation business intelligence (BI 2.0) applications.

Silverlight 4 Business Intelligence Soft 

Contact: bartczernicki@gmail.com

View Bart Czernickis profile on LinkedIn

NONE of the comments or opinions expressed here should be considered ofmy past or current employer(s).  The code provided is as-is without anyguarantees or warranties.

Sliverlight Multithreading with Controls (Slider example)

In the next couple of entries in my Silverlight Series, I am going to talk about multithreading, LINQ, etc., and how they can be used inside Silverlight to create rich applications.  However, I thought it might be a good idea to give a simple and well-explained example of before delving too much into why multithreading in Silverlight is important (vice versa). In this article, I want to briefly introduce multithreading inside Silverlight and the show how one can improve UI performance by introducing secondary threads into the events from UI controls.

Demo and Source Code are provided.

Update 10/14/2008..The demo is now on Silverlight 2 RTM and the Silverlight 2 Source Code is up.

Introduction

Silverlight runs as a plug-in inside the browser.  Some people describe it as "Flash" or a virtual desktop.  The virtual desktop is a good analogy to desktop (fat client) programming.  Those familiar with writing desktop applications know if you have long-running method calls (i.e., scanning the hard drive), making a database call or a web service call, that is done on the main UI thread by default.  Experienced developers know that making these calls on the main thread can cause the UI to become unresponsive or completely give the appearance of a blank UI window.  Creating a responsive UI usually entailed the desktop developer delving into mulithreading the background calls and keeping the main thread primarily to be used for UI operations.  Silverlight UI development shares these UI characteristics of desktop development.

The Silverlight team at Microsoft wants Silverlight to shine and perform "out of the box" by making the multithreaded choice for you. 

  • If you have done any kind of Silverlight service call, you already have a mental note that Silverlight already does a lot work for you on secondary threads.  Calling a WCF service or an ADO.NET Data Service is done on a secondary thread with all the events properly dispatching to the main thread.  This is a plus that developers not too familiar with .NET & multithreading can create responsive (in terms of UI) applications because they have no other choice :)
  • Silverlight takes this further and certain objects like the StoryBoard or Timers are also done on seperate threads.  This allows the developer/designer to create animations without having to worry about multithreading for performance as it is done for you. 
  • When you first hit a website that has Silverlight content, it will be brought down while a progress inidicator (whether it is the default or a custom implementation) shows how far along a user is in downloading content.  While the last example is not a true example of multithreading inside Silverlight, it does amplify the fact that Silverlight has a lot of multithreaded content "out of the box" and nudges the UI developer towards that way.

Not everything inside Silverlight multthreading is "out of the box" and a professional Silverlight developer has to understand that adding expensive calls based on UI controlled events will cause the Silverlight application to beome unresponsive.  Luckily Silverlight 2 includes a rich subset of the .NET 3.5 (SP1) stack and there are many options for developers dealing with multithreaded design.

Example & Demo with the Slider control

The Slider is a real basic control inside Silverlight.  You have seen the Slider implementated anywhere as a volume control or even as a query tool (i.e., Amazon diamond search).  A slider is designed to have a smooth user experience.  The user should be able to quickly move the slider thumb into position and clearly know what value they are on.

What if the movement of the slider thumb is associated with an expensive calculation, web service call or long LINQ query?  The demonstration below shows us three different sliders:

  • The first slider is a simple slider that performs a very quick output to the UI with how many times the move event was fired and the current value of the slider thumb.
    • Notice how many events are fired for just a simple "slide movement".
    • Just a simple movement from beginning to end can cause event handler to be called 30+ times (This depends on how slow you move the slider).
  • The second slider simulates a heavy operation.  It includes a 150ms operation inside the event handler method.
    • Notice the "sliding" movement operation is now seriously degraded.
    • The granularity of the slider is also impaired.  Because of the delay, it is harder to move the slider to the exact position we want.
    • Fast slider movement causes "big jumps" in the slider.
  • The third slider includes the EXACT same 150ms delay simulation.  The big difference is that the "heavy work" is done on a seperate thread and not on the main thread.
    • Notice the performance compared to the second slider.
    • The granularity and thumb movement is a lot better.  The user would not even notice that there is a significant process being done behind the scenes.
Code Overview

The source code is commented and self-explanatory for the most part. I do want to go over the multithreaded implementation in Silverlight.  Silverlight 2 Beta 2 currently does not support asynchronous delegates.  There are a few ways to write multithreaded processes.  The best way in Beta is probably utilizing the BackgroundWorker class.  Those familiar with desktop programming will be familiar with the implementation.  The BackgroundWorker automatically controls the secondary thread and properly threads dispatching through events/delegates.  It makes adding expensive processes on secondary threads trivial.

Let's go over some key parts of the code:

We declare the BackgroundWorker as a field, so it is properly scoped and can be used throughout the code file.  Furthermore, we want to wire up two events to their methods.  RunWorkerCompleted event fires after the work on the secondary thread has completed.  We can use this to get a result from the work or simply notify the UI that the process has finished.  The DoWork is the actual process that will be executed on the secondary thread.  This method will simulate the heavy work.

// declare background workerBackgroundWorker bw = new BackgroundWorker();public Page(){InitializeComponent();// wire up background worker eventsthis.bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);this.bw.DoWork += new DoWorkEventHandler(bw_DoWork);}

Now that we have the our BackGroundWorker defined and wired up to fire methods, we need to declare these two methods: 

  • The bw_DoWork method is pretty simple and just puts the current thread to sleep for 150 milliseconds.  Note that when you are in this thread, you are executing on the background thread not the main thread.  So this will put the secondary thread to sleep, not the main UI thread.  Furthermore, you cannot access any UI objects.  This will throw a cross-reference exception.
  • The bw_RunWorkerCompleted method is called after the 150 millisecond delay is complete.  This method is called on the main UI thread so it is safe to access UI objects.  What happens in this method is simple; Since I am done processing whatever my slider move caused, I simply notify the UI what the current value is.
    • Note the code calls itself again if the user moved the slider while the code was in the middle of processing on the second thread.
void bw_DoWork(object sender, DoWorkEventArgs e){// add a fake delay of 150 milliseconds (3/20 of a second)System.Threading.Thread.Sleep(150);}void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){// Set the slider value to its text box// Notice this is set here, as it guarantees that the value is now officially set// Setting it in the SliderMultiThreaded_ValueChanged event, the 2nd thread would have to catch up to the UIthis.txtSliderMultiThreadedValue.Text = this.SliderMultiThreaded.Value.ToString();// Run the background worker again in case the Slider value needs to catch up// If you stop the slider at the end, for example, it might be still processing the previous event// You want to make sure that where the slider is stopped (last event fired) matches what was processed by the 2nd threadif (!this.bw.IsBusy){// If the values are not in sync, then the 2nd thread needs to catch up to the UIif ((this.SliderMultiThreaded.Value != this.LastMultiThreadedSliderValue) && (this.LastMultiThreadedSliderValue != 0.0)){// Run the process again, if the last value set has not been run by the second threadthis.bw.RunWorkerAsync();// set the value to 0.0this.LastMultiThreadedSliderValue = 0.0;}}}

Kicking off the asynchronous process is simply done by calling the RunAsync() method on the BackgroundWorker variable (bw in our example) in the SliderMultiThreaded_ValueChanged event. This method is non-blocking on the UI thread and if you debug it, it will look like it finishes instantly. It actually spins up a secondary thread and performs the logic inside the bw_DoWork() method we defined above.  Notice below that the code only fires the asynchronous process if the BackGroundWorker is not busy.  This is key, as this will throw an exception if we try to kick off another process on the BackGroundWorker if it is not done.  This is why we have to do the "catch up" step above because the secondary thread could be busy processing the work while the user triggers another slider change event by moving the slider thumb.

private void SliderMultiThreaded_ValueChanged(object sender, RoutedPropertyChangedEventArgs e){// increment multi threaded slider event countthis.countSliderMultiThreaded++;// Set the last value set compared to the current valuethis.LastMultiThreadedSliderValue = this.SliderMultiThreaded.Value;// Execute the work on a second threadif (!bw.IsBusy){bw.RunWorkerAsync();}// Set the count on the text boxthis.txtSliderMultiThreadNumberEventFires.Text = this.countSliderMultiThreaded.ToString();}
Compare to other RIA  Technologies (Flex, Java)

How does this compare to Flash/Flex?  As of now even with Silverlight's limited multithreading support (Dispatcher, StoryBoards, BackgroundWorker, Services/Sockets, etc.), it actually is a lot better than Flash/Flex.  Flash/Flex DO NOT have multithreading support (at least as I understand it).  There is some multithreading in Flash 10 (which is also in beta).  I do not use Flash/Flex, from what I understand the new multithreading capabilites are more behind the scenes and do not include a first class multithreading and thread synchronization environment.  I was pretty suprised when I found that out and I see that is a huge problem for Flash/Flex. 

Many people who disagreed with me in my previous post when I listed the advantages of Silverlight over Flash at least agreed .NET favored Silverlight.  .NET is too much of a broad statement to simply state a simple advantage because of the MANY subpoints that .NET brings to Silverlight.  Simply saying .NET as an advantage is a big understatement. First class multithreading support is a huge win for Silverlight vs Flex/Flash.  Why does this matter?  Because any computer made in the last couple of years probably has a dual processor or more inside it.  It is all about adding cores not adding processing speed.  Silverlight takes advantage of this and it's only in beta!  You could write a similar slider application inside Flash/Flex with some tricks (using a resource govenor to manage the thread like context switching), but why would you want to??!!  Silverlight is already way ahead in the multithreading game compared to Adobe's RIA product.

JavaFX does have multithreading support for certain keywords used as triggers.  I wouldn't call it the same thing that Silverlight 2 RTM will offer.  However, JavaFX and Java can be used together and Java does offer full multithreading support.  Silverlight is nice in that it offers first class support all in one spot in one language.

Conclusion & Future

With this demo, I tried to drive home the point that in order to create the best UI experience for Silverlight users, ensure that you leverage all of the features inside the .NET Framework.  In my opinion, this is what makes Silverlight shine compared to other RIA technologies.  Silverlight 2.0 Beta 2 includes several options to add multithreading capabilities to your RIA applications.  Once delegates are added and are able to invoke methods asynchronously, this logic can become a lot more clearer and lot more functional looking (.NET 3.5 -> lambda expressions, etc.). 

In the RTM release I see Silverlight supporting full delegates with dynamic invoking and my hope is that PLINQ/Parallel Library will come to Silverlight as well.  If those two things happen, Silverlight will be the clear leader for multithreaded RIAs and allow you to write very performant applications.

kick it on DotNetKicks.com

Silverlight 2 Beta 2 Code: Silverlighthack_SlidersMultiThreadedExample.zip (545.41 kb)

Silverlight 2 RTM Code: Silverlighthack_SlidersMultiThreadedExample_RTM.zip (547.45 kb)

Posted: Sep 01 2008, 12:06 by Bart Czernicki | Comments (11) RSS comment feed |
  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us
blog comments powered by Disqus