using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Text; using System.Threading; using System.Windows.Forms; namespace AsyncCalcPiWithBackgroundWorkerSample { partial class AsyncCalcPiForm : Form { public AsyncCalcPiForm() { InitializeComponent(); } void ShowProgress(string pi, int totalDigits, int digitsSoFar) { // Make sure we're on the UI thread Debug.Assert(this.InvokeRequired == false); // Display progress in UI this.resultsTextBox.Text = pi; this.calcToolStripProgressBar.Maximum = totalDigits; this.calcToolStripProgressBar.Value = digitsSoFar; } class CalcPiUserState { public readonly string Pi; public readonly int TotalDigits; public readonly int DigitsSoFar; public CalcPiUserState(string pi, int totalDigits, int digitsSoFar) { this.Pi = pi; this.TotalDigits = totalDigits; this.DigitsSoFar = digitsSoFar; } } void CalcPi(int digits) { StringBuilder pi = new StringBuilder("3", digits + 2); // Report initial progress this.backgroundWorker.ReportProgress(0, new CalcPiUserState(pi.ToString(), digits, 0)); if( digits > 0 ) { pi.Append("."); for( int i = 0; i < digits; i += 9 ) { int nineDigits = NineDigitsOfPi.StartingAt(i + 1); int digitCount = Math.Min(digits - i, 9); string ds = string.Format("{0:D9}", nineDigits); pi.Append(ds.Substring(0, digitCount)); // Report continuing progress this.backgroundWorker.ReportProgress(0, new CalcPiUserState(pi.ToString(), digits, i + digitCount)); // Check for cancelation if( this.backgroundWorker.CancellationPending ) { return; } } } } void calcButton_Click(object sender, EventArgs e) { // Don't process if cancel request pending // (Should not be called, since we disabled the button...) if( this.backgroundWorker.CancellationPending ) { return; } // If worker thread currently executing, cancel it if( this.backgroundWorker.IsBusy ) { this.calcButton.Enabled = false; this.backgroundWorker.CancelAsync(); return; } // Set calculating UI this.calcButton.Text = "Cancel"; this.calcToolStripProgressBar.Visible = true; this.calcToolStripStatusLabel.Text = "Calculating..."; // Begin calculating pi asynchronously this.backgroundWorker.RunWorkerAsync( (int)this.decimalPlacesNumericUpDown.Value); } void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { //throw new Exception("Ooops!"); // Track start time DateTime start = DateTime.Now; CalcPi((int)e.Argument); // Indicate cancelation if( this.backgroundWorker.CancellationPending ) { e.Cancel = true; } // Return elapsed time DateTime end = DateTime.Now; TimeSpan elapsed = end - start; e.Result = elapsed; } void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { // Show progress CalcPiUserState progress = (CalcPiUserState)e.UserState; ShowProgress( progress.Pi, progress.TotalDigits, progress.DigitsSoFar); } void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // Reset progress UI this.calcButton.Text = "Calculate"; this.calcButton.Enabled = true; this.calcToolStripStatusLabel.Text = "Ready"; this.calcToolStripProgressBar.Visible = false; // Was the worker thread cancelled? if( e.Cancelled ) { this.resultsTextBox.Text = "Canceled"; return; } // Show elapsed time TimeSpan elapsed = (TimeSpan)e.Result; MessageBox.Show("Elapsed: " + elapsed.ToString()); } } }