Easy UI threading with Background Worker
Written by Mike James   
Friday, 01 October 2010
Article Index
Easy UI threading with Background Worker
Invoke and BackgroundWorker patterns
A bouncing ball example
Using BackgroundWorker
Going further

Banner

Going further

Of course this example isn't complete. We need some way of stopping the worker thread. We might even need some way of starting, stopping and restarting the worker.

This is all a matter of calling the worker's CancelAsync method and  checking the Cancellation Pending property of the sender object, that is:

bw.WorkerReportsProgress= true;
          
bw.DoWork += (o1, e1) =>
{                
do                
{                    
if (((BackgroundWorker)o1).
CancellationPending)
{
  e1.Cancel = true;
  break;
 }
 bw.ReportProgress(1, (object) vx);
  Thread.Sleep(10);
 } while (true);
};

and add another button and:

private void button2_Click(object sender, 
RoutedEventArgs e)
{  
bw.CancelAsync();
}

When the DoWork event handler terminates the RunWorkerCompleted event occurs and its event handler - running on the UI thread - gets a chance to do something.

Notice that if you are going to restart the worker then you certainly don't want to repeat all of the initialisation each time you restart it - just a call to RunWorkerAsync is all you need to restart. All of the initialisation should be in the constructor say. 

The complete program with this move of the initialisation  to the constructor is:

public MainPage()
{
InitializeComponent();
 bw.WorkerSupportsCancellation = true;
 bw.WorkerReportsProgress= true;
 bw.DoWork += (o1, e1) =>
{
  do
 {
 if (((BackgroundWorker)o1).
CancellationPending)
{
e1.Cancel = true;
   break;
   }
   bw.ReportProgress(1, (object) vx);
   Thread.Sleep(10);
 } while (true);
};
bw.ProgressChanged += new
ProgressChangedEventHandler(update);
}
int vx = 1;
 int vy = 1;
 private void button1_Click(object sender,
RoutedEventArgs e)
{
 bw.RunWorkerAsync();
 }
void update(object o,
ProgressChangedEventArgs e)
{
Canvas.SetLeft(rectangle1,
Canvas.GetLeft(rectangle1) + vx);
           Canvas.SetTop(rectangle1,
Canvas.GetTop(rectangle1) + vy);
 if(Canvas.GetLeft(rectangle1)<=0 ||
(Canvas.GetLeft(rectangle1)+
rectangle1.Width)>=
(canvas1.Width-1)) vx=-vx;
 if(Canvas.GetTop(rectangle1)<=0 ||
(Canvas.GetTop(rectangle1)+
rectangle1.Height)>=
(canvas1.Height-1)) vy=-vy;
}
private void button2_Click(object sender,
RoutedEventArgs e)
 {            
bw.CancelAsync();
 }
}

Also notice that you can pass any of the event handlers an object of your choice and this can be accessed via the event object.

To see how this works look out for a sample project to be published in a few days.

Finally notice that even this simple example has potential difficulties. While we follow the rule that only the UI thread ever works with UI objects both the UI and non-UI thread could in principle work with the global variables vx and vy.  In a more general case the UI thread in the ProgressChanged event handler and the non-UI thread in the DoWork event handler could access the same global shared objects. In this case you would need to use locking to prevent race conditions and be careful not to create a deadlock.

There is also the earlier problem of the worker thread overwhelming the UI thread with events. In practice this is unlikely to happen but not impossible.

Just because the BackgroundWorker object hides the threads and the threading doesn't mean that they aren't there.

We probably need an improved BackgroundWorker class that implements a safer and more sophisticated two thread solution to the UI worker interaction problem.

To access the code for this Silverlight project, once you have registered,  click on CodeBin.

If you would like to be informed about new articles on I Programmer you can either follow us on Twitter, onFacebook , on Digg or you can subscribe to our weekly newsletter.

 

Banner

<ASIN:073563887X>

<ASIN:0470650923 >

<ASIN:0470534044 >

<ASIN:1430225491 >

<ASIN:1430219505 >

<ASIN:1847199763 >

<ASIN:1430230185 >



Last Updated ( Friday, 01 October 2010 )