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)

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

Pete Brown - 23 April 2010

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.

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

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

  1. 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
  2. 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!
  3. 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.
  4. 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
  5. 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
  6. 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.
  7. 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]
  8. 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!
  9. 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 ?
  10. Georgesays:
    Interesting Thread!!! Thank you!
    I wonder how if this can solve issue: I get data (a lot) from DB from a domain context (ria services, EF) and I wait, and wait, and wait, and even the busy control blocks.
    Does anyone know how to make a request for RIA services with background worker (or any other solutions, smarter then the given idea).
    Thank you for all who will try!
    Thanks fo Pete for all the knowledge!
  11. Marksays:
    Pete - If I call a WCF service from a backgroundworker - where should the callback code be placed? In the _doWork event handler? When I do that it seems the thread never returns and the runworkercompleted event never gets tripped.

    Thanks
    Mark
  12. Petesays:
    @Mark

    I'm not sure what you mean by where it should be placed. It's just a method, place it in your code and let Silverlight call it. If you're doing it as a lambda, you could define it in the dowork handler if you want, but try with it as a regular method first.


    ...Dammit. I see two spam messages up top that I missed. I hate it when those sneak through. The comment management system in this version of umbraco is not good for old stuff.

    Pete
  13. Marksays:
    Thanks Pete - Turns out my backgroundworker was completing and firing the runworkercompleted event *before* the WCF service call returned. So a better question is when the service callback is fired, what thread is that on: the background thread that made the service call or the main UI thread? The behavior I'm seeing is that the background thread may be long gone by the time the service calls back. If that's true, then even though we call a service on a backgroundthread, the service callback should have access to page variables and UI Elements. Am I thinking straight?

    Mark

  14. Saurabhsays:
    Hi Pete,

    Thanx for the nice article.

    I am using these things in my silverlight application but I am stuck some where.

    I have a CommonSilverlight Class Library project which is used by difference silveright projects, and the CommonSilverlight Class library doesn't know whether the calling method is coming from UI Thread or Background Thread and in CommonSilverlight Class library we are calling some javascript method which is returning XML from server, If it comes from UI Thread then its working fine but if it comes from Background thread then there is a cross thread exception, we can not use Dispatcher.BeginInvoke method because it is a async method and method doesn't return me any xml because it fires after current method execution. we can not use SyncronizationContext here because SynchronizationContext must be declared in UI Thread.

    Do you have any other option to fix this issue.

    Kind Regards,
    Saurabh Kumar

Comment on this Post

Remember me