Welcome to Pete Brown's 10rem.net

First time here? If you are a developer or are interested in Microsoft tools and technology, please consider subscribing to the latest posts.

You may also be interested in my blog archives, the articles section, or some of my lab projects such as the C64 emulator written in Silverlight.

(hide this)

23 Apr 2010

Essential Silverlight and WPF Skills: The UI Thread, Dispatchers, Background Workers and Async Network Programming

         

I'm starting a occasional series of postings on top things every Silverlight and WPF developer should know. Originally, I was going to make this a top-10 style list, but I'll keep that for my presentations, and instead expand on it here, with one topic per post.

This one is about threading in Silverlight.

Ok, that subject sounds like a lot, but it's all pretty closely related.

Both Silverlight and WPF have the concept of a UI thread. Whenever you tie that thread up, you make your application unresponsive. In Silverlight, if you're on a page with other plug-ins, you make all the plug-ins unresponsive. (It's actually per-process, but most modern browsers separate processes by tabs)

Async Network Calls

In order to keep from tying up the UI thread, you have to perform long-running processes on another thread. Often, but not always, those processes are network calls. In Silverlight, all network calls are async with no provision to handle them any other way. This lets you off the hook threading-wise, but requires that you understand how to chain those calls, and how to deal with libraries that have IAsyncResult callbacks that return on different threads.

TestServiceClient client = new TestServiceClient();
client.DoSomethingSlowCompleted += (s, ea) =>
    {
        // do something with the results here
        Debug.WriteLine(ea.Result);
    };

client.DoSomethingSlowAsync();

Background Worker

For other processes, the BackgroundWorker is a great, simple, way to do some background work while reporting progress to the UI. It takes all the dispatching work away, so you can feel free to manipulate the UI from the ProgressChanged and RunWorkerCompleted events. Do not touch the UI from the DoWork event, as that is actually running on a separate thread.

private BackgroundWorker _worker = new BackgroundWorker();
private void RunLongProcess()
{
    _worker.WorkerReportsProgress = true;

    ProgressBar.Minimum = 0;
    ProgressBar.Maximum = 100;

    _worker.DoWork += (s, e) =>
        {
            for (int i = 0; i < 100; i++)
            {
                // simulate long-running work
                System.Threading.Thread.Sleep(500);
                ((BackgroundWorker)s).ReportProgress(i+1);
            }

        };

    _worker.ProgressChanged += (s, e) =>
        {
            // this is on the UI thread, so you can
            // update UI from here.
            ProgressBar.Value = e.ProgressPercentage;
        };

    _worker.RunWorkerCompleted += (s, e) =>
        {
            // clean up after your stuff, yes, you can touch UI here.                
        };

    _worker.RunWorkerAsync();
        
}

Of course, knowing how to set up event handlers using lambda expressions is always helpful :)

Dispatcher

Sometimes, you spin off a thread of your own, or you have to deal with some of the crufty stacks where the callbacks come back on a different thread from the one that created the call. In those cases, you need to use a dispatcher to make a call back to the UI thread.

If the code is on a page, you can call the dispatcher property and pass it a function to execute (yes, more lambda in this example).

private void UpdateUI()
{
    Dispatcher.BeginInvoke(() =>
        {
            ProgressBar.Value = 50;
        });
}

But, if the code is in some sort of non-UI class, it gets more complex. You can do it this way, using a dummy control (like we did in Silverlight 2):

TextBlock _dispatcherObject = new TextBlock();
private void UpdateUINasty() // avoid this approach unless it's all you've got
{
    _dispatcherObject.Dispatcher.BeginInvoke(() =>
        {
            SomePage.ProgressBar.Value = 50;
        });
}

This example assumes the object itself was created on the UI thread. The better way is to use the Deployment object:

private void UpdateUINotSoNasty()
{
    Deployment.Current.Dispatcher.BeginInvoke(() =>
    {
        SomePage.ProgressBar.Value = 50;
    });
}

That's better. Definitely the recommended approach for recent versions of Silverlight, including Windows Phone 7.

Timers

What about when you need to run something on a timer? The normal timer classes require manual dispatching to do any UI updates. However, Silverlight and WPF both have the DispatcherTimer class that handles all that for you.

private void StartTimer()
{
    DispatcherTimer timer = new DispatcherTimer();

    timer.Tick += (s, e) =>
        {
            // do some very quick work here

            // update the UI
            StatusText.Text = DateTime.Now.Second.ToString();
        };

    timer.Interval = TimeSpan.FromSeconds(1);
    timer.Start();
}

Of course, realize that what you're doing here is interrupting the UI thread, not really running anything on a separate thread. It's not suitable for anything long-running and cpu-intensive, but rather something where you need to execute on a regular interval. Clock UI updates are a perfect example.

Threads

In general, I discourage folks from spinning off real threads. Very few people understand how to efficiently work with threads, so even if you're a threading genius, the person coming in after you probably isn't. In most cases, the Background Worker will provide you with what you need.

Silverlight doesn't yet have it, but the Parallel Tasking support built into .NET 4 can really help you out should you really need to do more than two things at once. Definitely check it out.

Conclusion

Threading in Silverlight and WPF is a little trickier than some other technologies, because you have to worry about the UI thread. My intention here was to both inform you that this trickiness exists, and then show some ways of dealing with it.

Share |
posted by Pete Brown on Friday, April 23, 2010
filed under:          

21 comments for “Essential Silverlight and WPF Skills: The UI Thread, Dispatchers, Background Workers and Async Network Programming”

  1. Clint Rutkassays:
    What about ThreadPool? Background worker only can do so much
  2. Petesays:
    @Clint

    I really try and get folks new to SL/WPF to stay away from "real" threading, that includes ThreadPool.

    If you're in WPF, you can do more with the parallel extensions in most cases. I'd recommend looking at that before even thinking about custom threads. As we get more cores, it's going to be more and more important to just tell the CPU that we need to do something in parallel and let it figure out how many threads can be effectivly used on the machine.

    If you really know threads enough to handle all the "other" stuff that comes along with them, like cancellation, updating shared data etc. then go for it. Otherwise, I strongly recommend the other approaches.

    That said, I use a single separate thread in the Silverlight C64 emulator precisely because I do know why it's there and how to manage it :)

    Pete
  3. Jonahsays:
    It's kind of misleading in your Dispatcher section to say "In those cases, you need to use a dispatcher to make a call back to the UI thread."

    You don't really *need* Dispatcher, you just need to marshal your call back to the UI thread and the Dispatcher is one way to do that. I find SynchronizationContext just as easy to use as Dispatcher and SynchronizationContext has the added benefit of being unit testable without relying on the existence of a DispatcherObject somewhere in the current AppDomain. Unit testing ViewModels that use Dispatcher is problematic at best. Caveat: I mostly work in WPF, so I can't comment on Deployment.Current.

    Otherwise, great article. Strategies for moving work off/on the UI thread is a skill that more devs should understand.

    Cheers!
  4. Petesays:
    @Jonah

    Good point. Thanks for the correction and clarification.

    Pete
  5. Lee Englestonesays:
    Fantastic! I'm learning WPF and this us one of the first hurdles I encountered when mixing UI with long running processes. Currently using the BackgroundWorker but will try Dispatcher.

    -- Lee
  6. Dennysays:
    Yeah, i have used the backgound worker in many many apps....
    i use it in services and in winforms apps all the time.

    and yeah if you do not unerstand threading it can be a tricky mess to manage and make it really stable.
    if you can avoid it then do.

    if you really need to then make sure you know what it's doing.
  7. Bart Czernickisays:
    @Pete,

    I will also add that the Dispatcher object is in the UI class for bot Silverlight/WPF. Therefore, when creating assemblies using this technique you will need to reference the System.Windows.UI (I think assembly) just to do Dispatcher. This is why SynchronizationContext is best practice for most scenarios.

    Dispatcher has one less line of code that is why its always seen in blogs/articles. No need for this:
    SynchrnizationContext syncContext = SynchronizationContext.Current;

    -- Bart Czernicki
  8. Mark Wisecarversays:
    You're doing a great job Pete, thanks. ;-)
  9. Carstensays:
    Hi,

    sure you are right when saying "don't use threads unless you know how" - but I would put it rather: "learn how to use threads if you don't allready before using those" instead.
    No use hiding from conurency these days - embrace and learn this stuff - sooner or later you have to and the TPL, parallel LINQ, etc. won't do anything for you if you don't understand the basic problems.

    BTW: if you don't allready have, take a look at F# that comes with very powerful tools to help you get around some of the problemes with Sync.context etc. you mentioned (Async.SwitchToContext with a closure on the calling Sync.context comes to mind ;) )

    Best regards
  10. Boyclinnifolosays:
    best web page just for you
    I apologise, that I can help nothing. I hope, to you here will help. Do not despair.
    [url=http://atrovent.h.gp/339/index.html]west pharmacy virginia o[/url]

    See you later
  11. suiqueSquappysays:
    Hello.

    Im new in forum, so Im not sure if I can post this here in general..
    But to the point, what I was asking.. Im from europe and would like to buy things eg. from amazon and ebay, so is it easy and safe to buy with my credit card?
    And if you know good methods to buy things..[IMG]http://netti-kasinot.net/prkl/e3.GIF[/IMG] Pls tell me.

    Thanks in advance!
  12. modesisays:
    Hip Mean - Secret Make, Ideas, Styles, Architecture
  13. Svetaprettygirlsays:
    Please! Leave more information and more links about next themes:
    1. dating fender deluxe reverb
    2. get my ex boyfriend back advice
    3. algoa dating buzz
    4. senior dating network
    5. beautiful women dating service
  14. weddinerzsays:
    The Channel 4 ski team will take an in depth look at the new generation of Canucks in our Canadian Cowboys feature.
    [URL=http://wedding.ooo.com]elizabeth cronin karner wedding marriage missouri[/URL]
    Greg Swingle Check Out The Live Webcam Views of The Mountain at Ohio Ski Resorts.
  15. Jitendrasays:
    This is great UI Thread B'coz I am looking this kind of UI Updated thread and i got it but how i can use in
    for loop this thread ,,


    Thanks...
  16. AcrodoBomsays:
    Fajna stronka lecz dla polepszenia skutecznosci i reklamy zapraszam do skorzystania z naszej oferty np: [url=http://www.cyberpozycja.pl]Pozycjonowanie stron www[/url] na pewno jestesmy konkurencyjni.
  17. cowRIOsays:
    [b][url=http://www.utrechttandarts.nl/tandartsen/tandartspraktijk-galgenwaard]tandartspraktijk galgenwaard[/url][/b]
    [b][url=http://www.utrechttandarts.nl/tandartsen/tandartspraktijk-staalwijk]staalwijk[/url][/b]
    [b][url=http://www.utrechttandarts.nl/tandartsen/tandartspraktijk-staalwijk]tandartspraktijk staalwijk[/url][/b]
  18. Buinnagatsays:
    Hello all! I like this forum, i organize multifarious interesting people on this forum.!!!

    Large Community, good all!
  19. dotNet Followersays:
    Hello!
    Thank you for useful and very detailed post. <a href="http://dotnetfollower.com/wordpress/2011/07/silverlight-for-windows-phone-7-how-to-check-if-the-current-thread-is-ui-one/">Here</a> a couple of words about Dispatcher.CheckAccess().

    Thank you!
  20. frictiorbsays:
    The way to Use ELM327 OBD-II OBD2 CAN USB Interface Diagnostic Tool

    ELM327 OBD-II OBD2 CAN USB Interface Diagnostic Tool is extremely straightforward to make use of. Just turn your computer into a car diagnostic method. This interface with software included is all you will need. Works for many of cars soon after 1996. It can read and clear all diagnostic trouble codes. Display all of the live information of your vehicle.

    ELM 327 Instructions:

    There are many software for running [url=http://www.dandebiz.com/elm327.html]ELM327[/url], now we're talking about software program EasyobdII two.2 version.

    1. First, Connect your laptop with your auto and turn the important on or turn the engine to be running.

    two. The hardware will likely be detected and automatically installed, ready to utilize. Otherwise, you must use driver file to install it.

    three. If you happen to use Windows Vista, only the software program EasyobdII 2.two works with Vista. For rest operation method really should not such troubles.

    four. In the 1st attempt, you might have difficulty and see screen like the following.

    You will find 5 alternatives like com1, com2, ...com5.

    5. At this step, you'll need Go to Control Panel--> program --> Device manager -->Ports(Com&LPT) --> USB serial port(com?), to discover which com number you'll need choose.

    6. If the above com number is com1, Restart program EasyobdII, choose COM port as com#1 at bottom line of program, and let the program detect automobile ECU.

    7. The method will generate data and shows on screen.

    8. Other thing to try: plug and unplug [url=http://www.dandebiz.com/obd-connector.html]OBD Connector[/url] and make sure connection is OK; or attempt a different usb port of your laptop.
  21. Nik Kokkinossays:
    Hallo Pete,

    I found your article , when I was searching for thoughts and solurtions around threads and the Backgroundworker class for Silverlight. I want to express my Problem that I have and if you or an other guy who follows the article can help me to find a solution.
    So my Use Case is as follows:
    - The Application is able to export Framework Elements as Pdf file, using the OpenDialog class . Its page on the Pdf file is a rendered Image of each Framework Element. To do that I use the Telerik Function for exporting to Pdf. This function has the following signature: void Export(Raddocument document, Filestream stream). In this function the parameter document is the generated Pdf document and stream is the Filestream from the opendialog class.
    - When the stream is written to the Hard disk after the User hits the Ok button in the Open Dialog the UI Window of my Silverlight application freezes for a while ( the time it needs for writing the file on the disk) .
    - I tried to use according to your Blog article the Background calss and the Dispatcher , but I got Security exceptions...
    - What can I do , so that the time it needs for the Stream to be written on the Disk , an indicator can inform the user with update progress without freezing ?

Comment on this Post

Remember me