Click to Rate and Give Feedback
MSDN
MSDN Library
.NET Development
Silverlight
Performance
 How to: Use a Background Worker
Collapse All/Expand All Collapse All
Silverlight
How to: Use a Background Worker

The Silverlight BackgroundWorker class provides an easy way to run time-consuming operations on a background thread. The BackgroundWorker class enables you to check the state of the operation and it lets you cancel the operation.

When you use the BackgroundWorker class, you can indicate operation progress, completion, and cancellation in the Silverlight user interface. For example, you can check whether the background operation is completed or canceled and display a message to the user.

To use the BackgroundWorker class

  1. At the class level, create an instance of the BackgroundWorker class.

    Visual Basic
    Dim bw As BackgroundWorker = New BackgroundWorker
    C#
    BackgroundWorker bw = new BackgroundWorker();
  2. Specify whether you want the background operation to allow cancellation and to report progress.

    Visual Basic
    bw.WorkerSupportsCancellation = True
    bw.WorkerReportsProgress = True
    C#
    bw.WorkerSupportsCancellation = true;
    bw.WorkerReportsProgress = true;
  3. Create an event handler for the background worker's DoWork event.

    The DoWork event handler is where you run the time-consuming operation on the background thread. Any values that are passed to the background operation are passed in the Argument property of the DoWorkEventArgs object that is passed to the event handler.

    To report progress back to the calling process, call the ReportProgress method and pass it a completion percentage from 0 to 100. Calling the ReportProgress method raises the ProgressChanged event, which you handle separately.

    NoteNote:

    If the background worker's WorkerReportsProgress property is not set to true and you call the ReportProgress method, an exception will occur.

    To determine if there is a pending request to cancel the background operation, check the CancellationPending property of the BackgroundWorker object. If the property is true, the CancelAsync method was called. Set the BackgroundWorker object's Cancel property to true and stop the operation.

    To pass data back to the calling process, set the Result property of the DoWorkEventArgs object that is passed to the event handler. This value can be read when the RunWorkerCompleted event is raised at the end of the operation.

    Visual Basic
    Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
    
        For i = 1 To 10
            If bw.CancellationPending = True Then
                e.Cancel = True
                Exit For
            Else
                ' Perform a time consuming operation and report progress.
                System.Threading.Thread.Sleep(500)
                bw.ReportProgress(i * 10)
            End If
        Next
    End Sub
    
    C#
    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;
    
        for (int i = 1; (i <= 10); i++)
        {
            if ((worker.CancellationPending == true))
            {
                e.Cancel = true;
                break;
            }
            else
            {
                // Perform a time consuming operation and report progress.
                System.Threading.Thread.Sleep(500);
                worker.ReportProgress((i * 10));
            }
        }
    }
    
  4. Create an event handler for the background worker's ProgressChanged event.

    In the ProgressChanged event handler, add code to indicate the progress, such as updating the user interface.

    To determine what percentage of the operation is completed, check the ProgressPercentage property of the ProgressChangedEventArgs object that was passed to the event handler.

    Visual Basic
    Private Sub bw_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
        Me.tbProgress.Text = e.ProgressPercentage.ToString() & "%"
    End Sub
    
    C#
    private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.tbProgress.Text = (e.ProgressPercentage.ToString() + "%");
    }
    
  5. Create an event handler for the RunWorkerCompleted event.

    The RunWorkerCompleted event is raised when the background worker has completed. Depending on whether the background operation completed successfully, encountered an error, or was canceled, update the user interface accordingly.

    To determine whether an error occurred, check the Error property of the RunWorkerCompletedEventArgs object that was passed to the event handler. If an error occurred, this property contains the exception information.

    If the background operation allows cancellation and you want to check whether the operation was canceled, check the Cancelled property of the RunWorkerCompletedEventArgs object that was passed to the event handler. If the property is true, the CancelAsync method was called.

    Visual Basic
    Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
        If e.Cancelled = True Then
            Me.tbProgress.Text = "Canceled!"
        ElseIf e.Error IsNot Nothing Then
            Me.tbProgress.Text = "Error: " & e.Error.Message
        Else
            Me.tbProgress.Text = "Done!"
        End If
    End Sub
    
    C#
    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if ((e.Cancelled == true))
        {
            this.tbProgress.Text = "Canceled!";
        }
    
        else if (!(e.Error == null))
        {
            this.tbProgress.Text = ("Error: " + e.Error.Message);
        }
    
        else
        {
            this.tbProgress.Text = "Done!";
        }
    }
    
  6. Add the event handlers to the BackgroundWorker instance's events.

    The following example shows how to add the event handlers to the DoWork, ProgressChanged, and RunWorkerCompleted events.

    Visual Basic
    AddHandler bw.DoWork, AddressOf bw_DoWork
    AddHandler bw.ProgressChanged, AddressOf bw_ProgressChanged 
    AddHandler bw.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted
    C#
    bw.DoWork += 
        new DoWorkEventHandler(bw_DoWork);
    bw.ProgressChanged += 
        new ProgressChangedEventHandler(bw_ProgressChanged);
    bw.RunWorkerCompleted += 
        new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
  7. Start running the background operation by calling the RunWorkerAsync method.

    Visual Basic
    Private Sub buttonStart_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        If Not bw.IsBusy = True Then
            bw.RunWorkerAsync()
        End If
    End Sub
    
    C#
    private void buttonStart_Click(object sender, RoutedEventArgs e)
    {
        if (bw.IsBusy != true)
        {
            bw.RunWorkerAsync();
        }
    }
    
  8. Cancel the background operation by calling the CancelAsync method.

    Visual Basic
    Private Sub buttonCancel_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        If bw.WorkerSupportsCancellation = True Then
            bw.CancelAsync()
        End If
    End Sub
    
    C#
    private void buttonCancel_Click(object sender, RoutedEventArgs e)
    {
        if (bw.WorkerSupportsCancellation == true)
        {
            bw.CancelAsync();
        }
    }
    

The following example shows how to use the BackgroundWorker class. In the example, the background operation runs the Sleep method and reports progress to the user interface. The background worker is configured to allow cancellation.

Visual Basic
Imports System.ComponentModel

Partial Public Class Page
    Inherits UserControl
    Private bw As BackgroundWorker = New BackgroundWorker

    Public Sub New()
        InitializeComponent()

        bw.WorkerReportsProgress = True
        bw.WorkerSupportsCancellation = True
        AddHandler bw.DoWork, AddressOf bw_DoWork
        AddHandler bw.ProgressChanged, AddressOf bw_ProgressChanged
        AddHandler bw.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted

    End Sub
    Private Sub buttonStart_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        If Not bw.IsBusy = True Then
            bw.RunWorkerAsync()
        End If
    End Sub
    Private Sub buttonCancel_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        If bw.WorkerSupportsCancellation = True Then
            bw.CancelAsync()
        End If
    End Sub
    Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)

        For i = 1 To 10
            If bw.CancellationPending = True Then
                e.Cancel = True
                Exit For
            Else
                ' Perform a time consuming operation and report progress.
                System.Threading.Thread.Sleep(500)
                bw.ReportProgress(i * 10)
            End If
        Next
    End Sub
    Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
        If e.Cancelled = True Then
            Me.tbProgress.Text = "Canceled!"
        ElseIf e.Error IsNot Nothing Then
            Me.tbProgress.Text = "Error: " & e.Error.Message
        Else
            Me.tbProgress.Text = "Done!"
        End If
    End Sub
    Private Sub bw_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
        Me.tbProgress.Text = e.ProgressPercentage.ToString() & "%"
    End Sub
End Class
C#
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

namespace SL_BackgroundWorker_CS
{
    public partial class Page : UserControl
    {
        private BackgroundWorker bw = new BackgroundWorker();

        public Page()
        {
            InitializeComponent();

            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = true;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        }
        private void buttonStart_Click(object sender, RoutedEventArgs e)
        {
            if (bw.IsBusy != true)
            {
                bw.RunWorkerAsync();
            }
        }
        private void buttonCancel_Click(object sender, RoutedEventArgs e)
        {
            if (bw.WorkerSupportsCancellation == true)
            {
                bw.CancelAsync();
            }
        }
        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            for (int i = 1; (i <= 10); i++)
            {
                if ((worker.CancellationPending == true))
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    // Perform a time consuming operation and report progress.
                    System.Threading.Thread.Sleep(500);
                    worker.ReportProgress((i * 10));
                }
            }
        }
        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if ((e.Cancelled == true))
            {
                this.tbProgress.Text = "Canceled!";
            }

            else if (!(e.Error == null))
            {
                this.tbProgress.Text = ("Error: " + e.Error.Message);
            }

            else
            {
                this.tbProgress.Text = "Done!";
            }
        }
        private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.tbProgress.Text = (e.ProgressPercentage.ToString() + "%");
        }
    }
}
XAML
<UserControl x:Class="SL_BackgroundWorker_CS.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel Height="30" Orientation="Horizontal" 
                    HorizontalAlignment="Left" VerticalAlignment="Top" 
                    Margin="10" >
            <Button x:Name="buttonStart" Content="Start" Click="buttonStart_Click"
                    Width="80" Height="30"/>
            <Button x:Name="buttonCancel" Content="Cancel" Click="buttonCancel_Click"
                    Width="80" Height="30"/>
        </StackPanel>
        <StackPanel Margin="10,50,0,0" Orientation="Horizontal">
            <TextBlock Text="Progress: "/>
            <TextBlock x:Name="tbProgress"/>
        </StackPanel>
    </Grid>
</UserControl>
XAML
<UserControl x:Class="SL_BackgroundWorker_VB.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel Height="30" Orientation="Horizontal" 
                    HorizontalAlignment="Left" VerticalAlignment="Top" 
                    Margin="10" >
            <Button x:Name="buttonStart" Content="Start" Click="buttonStart_Click"
                    Width="80" Height="30"/>
            <Button x:Name="buttonCancel" Content="Cancel" Click="buttonCancel_Click"
                    Width="80" Height="30"/>
        </StackPanel>
        <StackPanel Margin="10,50,0,0" Orientation="Horizontal">
            <TextBlock Text="Progress: " />
            <TextBlock x:Name="tbProgress" />
        </StackPanel>
    </Grid>
</UserControl>

Reference

Other Resources

Tags What's this?: Add a tag
Community Content   What is Community Content?
Add new content RSS  Annotations
How does one set DoWorkEventArgs.Argument?      David Ziffer   |   Edit   |   Show History
The DoWorkEventArgs parameter has a property called Argument which is presumably intended to allow the actual time-consuming working function to take an argument from its environment. However this article, like all other articles I've seen on the subject of BackgroundWorker, shows us only an example of a useless work function that requires no arguments, and consequently the article can afford to neglect to show us how e.Argument would get set (i.e. how do I control the contents of the DoWorkEventArgs parameter when the "DoWork" event fires?). An example of this would be greatly appreciated.
Tags What's this?: Add a tag
Flag as ContentBug
Code Snippet boxes are duplicated      João Paulo Menezes   |   Edit   |   Show History
There are duplicated code snippet boxes, one for VB.NET and another for C#

If VB.NET is selected, the first box shows the VB.NET code and the other shows "No code example is currently available or this language may not be supported."

Else if C# is selected, the second box shows the C# code and the first box shows "No code example is currently available or this language may not be supported."

Weren't these two boxes supposed to be only one, with the content code changing accordingly with the selected language?
Tags What's this?: Add a tag
Flag as ContentBug
Example of more general use of Background Worker      infomax   |   Edit   |   Show History

Following up the comment about which thread runs which event handler the following tutorial explains the how and why and some of the potential problems in using Background Worker - it may hide the fact that you are using threading but you can't avoid the responsibility.

http://www.i-programmer.info/programming/silverlight/1388-easy-ui-threading-with-background-worker.html

Tags What's this?: Add a tag
Flag as ContentBug
Why use this complicated class?      LukePuplett ... Thomas Lee   |   Edit   |   Show History

The article is a good-un, but it neglects to explain why you'd want (or more accurately: need) to jump through all these hoops to start some asynchronous plates spinning.

The answer is that the thread that fires the event DoWork is not the same thread that fires either the ProgressChanged or RunWorkerCompleted. The latter two are fired on the UI thread (or the thread the RunWorkerAsync method was called from), whereas the DoWork is called on a threadpool thread.

This is important because in Windows development (and I assume Silverlight on any platform) you must update UI controls on the UI thread (because the (old) system is a single-threaded "message pumping" mechanism).

Processing
© 2012 Microsoft. All rights reserved. Terms of Use | Trademarks | Privacy Statement
Page view tracker