BackgroundWorker Sample

Wed, December 29, 2004, 06:46 PM under MobileAndEmbedded
You should be familiar by now with Whidbey's excellent BackgroundWorker class and my implementation of it for the Compact Framework 1.0 - for immediate use today :-)

Although the MSDN examples and walkthroughs (as described on the above link) are great, I thought I would port Chris Sells's sample from the excellent article he wrote a while back: Asynchronous Calculation of PI digits. I encourage you to download the code from that article and compare it against the code I present here. It will instantly become apparent what power the BackgroundWorker brings in terms of simple code to write, read and maintain (let alone understand, but that might be a drawback depending on your outlook :-).

The form looks like this.

You can download the project at the end of this entry, but here is all of the relevant code (works on both CF and desktop):
        // Declare the worker
private BackgroundWorker mBW;

// Call this method in form's ctor
private void InitBW(){
mBW = new BackgroundWorker(this);
mBW.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(mBW_RunWorkerCompleted);
mBW.ProgressChanged
+= new ProgressChangedEventHandler(mBW_ProgressChanged);
mBW.DoWork += new DoWorkEventHandler(mBW_DoWork);
mBW.WorkerReportsProgress = true;
mBW.WorkerSupportsCancellation = true;
}

// Handles click for Calc/Cancel button
private void cmdCalc_Click(object sender, System.EventArgs e) {
if (cmdCalc.Text == "Calc"){
// read digits from numeric updown control
int digits = (int)nuDigits.Value;
pbLeft.Maximum = digits;
// ask worker to do its job
mBW.RunWorkerAsync(digits);
cmdCalc.Text = "Cancel";

}else if (cmdCalc.Text == "Cancel"){
// ask worker to cancel
cmdCalc.Enabled = false;
mBW.CancelAsync();

}else{
// Only two enabled states for
// this button: Calc and Cancel
System.Diagnostics.Debug.Assert(false);
}
}

// Completion event
private void mBW_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e) {
// Just get ready for next time
cmdCalc.Text = "Calc";
cmdCalc.Enabled = true;
}

// Progress event
private void mBW_ProgressChanged(object sender,
ProgressChangedEventArgs e) {
// Touch GUI, no problem
pbLeft.Value = e.ProgressPercentage;
txtPi.Text = (string)e.UserState;
}

// On worker thread! Only method with real logic
private void mBW_DoWork(object sender, DoWorkEventArgs e) {
int digits = (int)e.Argument;
BackgroundWorker bw = (BackgroundWorker)sender;

// we will be updating the UI with progress
string pi = "3";

// Show progress (ignoring Cancel so soon)
bw.ReportProgress(0, pi);

if( digits > 0 ) {
pi += ".";

for( int i = 0; i < digits; i += 9 ) {
// Work out pi. Scientific bit :-)
int nineDigits = NineDigitsOfPi.StartingAt(i + 1);
int digitCount = System.Math.Min(digits - i, 9);
string ds = System.String.Format("{0:D9}", nineDigits);
pi += ds.Substring(0, digitCount);

// Show progress
bw.ReportProgress(i + digitCount, pi);

// Deal with possible cancellation
if (bw.CancellationPending == true){
e.Cancel = true;
break;
}
}
}

}

Download the project (zip).