Using BackgroundWorker with WPF

In this article i will cover the simple use of the BackgroundWorker Class. This is really useful if for example you want to perform some tasks on another thread while keeping the UI Thread responsive. I will show you the example code and then try and break it down to make it understandable.

    public partial class Page1 : Page 
    {
        private BackgroundWorker worker = new BackgroundWorker();
        private delegate void Progress(int? info);

        public Page1() {
            InitializeComponent();
        }
        
        public void ProgressInfo(int? info) {
            //Update the UI Thread
            //Update some control with the value of info
        }

        public void PerformTask() {
            System.Windows.Threading.Dispatcher context = this.Dispatcher;

            worker.DoWork += (sender, eventArgs) =>
            {
                int counter = 0;
                Progress updateProgress = new Progress(ProgressInfo);

                for (var i = 0; i < 10; i++) {
                    System.Threading.Thread.Sleep(1000);
                    counter++;
                    context.Invoke(updateProgress, counter);
                }

            };
            worker.RunWorkerCompleted += (sender, eventArgs) =>
            {
                Progress updateProgress = new Progress(ProgressInfo);
                context.Invoke(updateProgress, null);
            };

            worker.RunWorkerAsync();
        }
    }

So whats this doing. Assume that we have a controld on the form which we want to update during the processing of our code so that the user knows something is happening.
For the purposes of this example i have not included the form code.

Working from the top down.

        private BackgroundWorker worker = new BackgroundWorker();
        private delegate void Progress(int? info);

We create an instance of the BackgroundWorker class and a new Delegate which will (in this instance) accept a nullable int.

We then have a very basic method called ProgressInfo, notice that this method takes the same nullable int as the Delegate, this will be used later.

     public void ProgressInfo(int? info) {
            //Update the UI Thread
            //Update some control with the value of info
     }

We need this method in order to allow us to talk to the controls on the form which are running on the UI Thread. Remember, as soon as we use the BackgroundWorker class we are creating another thread, its doing all the hard work for us.

Inside the PerformTask method the first thing we do is set a reference to the Dispatcher. The Dispatcher, as its name suggests is responsible for listening for various messages, it proxies the messages to any object on the UI Thread that may need it.

System.Windows.Threading.Dispatcher context = this.Dispatcher;

The DoWork event which is a member of the BackgroundWorker class allows us to specify what we want to happen on the new thread, this means that anything that happens inside the DoWork delegate cannot access the UI Thread directly.

   worker.DoWork += (sender, eventArgs) =>
            {
                int counter = 0;
                Progress updateProgress = new Progress(ProgressInfo);

                for (var i = 0; i < 10; i++) {
                    System.Threading.Thread.Sleep(1000);
                    counter++;
                    context.Invoke(updateProgress, counter);
                }

            };

In this example, we create a new instance of the Progress Delegate using the ProgressInfo method a parameter, this is what we will be calling later.
The basic example shown above is a simple loop from 0 to 10 with a 1 second pause, and during each iteration we increment a counter by 1 and then use the Dispatcher (remember that we called the reference to the Dispatcher “context” in the previous code snippet) to invoke the delegate updateProgress.

The call to “invoke” will call into the ProgressInfo(int? info) method passing in the current number held in the counter variable.

We can also add a new delegate “RunWorkerCompleted”, in this example we create a new instance of the delegate we used in the DoWork delegate and pass through a null, Now the code in the ProgressInfo method could check for this value and perform some action.
This delegate doesnt really need to be specified, but i did just to demonstrate something with it.

            worker.RunWorkerCompleted += (sender, eventArgs) =>
            {
                Progress updateProgress = new Progress(ProgressInfo);
                context.Invoke(updateProgress, null);
            };

And finally the thing that makes the BackgroundWorker “work”. We need to call RunWorkerAsync() in order to spawn the new thread.

worker.RunWorkerAsync();

I hope that all made sense.