March 20, 2010 by Christoff Truter C# Threading
Running intensive tasks like database transactions, uploads/downloads etc, on the
same thread as your UI, can cause your UI to become unresponsive.
To solve this issue, we can move these intensive tasks to separate/background threads.
For this purpose we can use the BackgroundWorker component/class, which you can drop
to your form from the toolbox within Visual Studio - or simply create an instance
of the BackgroundWorker class.
Lets have a quick look, at the demo code that you can download at the top of the post. We're going to create a small little application like this:
BackgroundWorker bw = new BackgroundWorker(); public mainForm() { InitializeComponent(); bw.DoWork += new DoWorkEventHandler(bw_DoWork); bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); bw.WorkerReportsProgress = true; bw.WorkerSupportsCancellation = true; } private void btnGo_Click(object sender, EventArgs e) { if (cbxWorker.Checked) { if (!bw.IsBusy) // If the thread isn't started, start it { bw.RunWorkerAsync(); } } else { // What would happen if we didn't use a background thread? for (int i = 0; i < 50; i++) { Thread.Sleep(100); lbxItems.Items.Insert(0, i); } } }Notice the attached events, DoWork & ProgressChanged.
void bw_DoWork(object sender, DoWorkEventArgs e) { for (int i = 0; i < 50; i++) { Thread.Sleep(100); // Some intensive task if (bw.CancellationPending) { e.Cancel = true; } if (!e.Cancel) { bw.ReportProgress(i); // Inform the main thread of our progress } else { break; } } }
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) { lbxItems.Items.Insert(0, e.ProgressPercentage); }You might have noticed the CancellationPending property in the bw_DoWork method, this property informs us if the background process must still continue or if its been cancelled - which allows us to gracefully handle the cancellation of the background thread.
private void btnStop_Click(object sender, EventArgs e) { bw.CancelAsync(); }
void addItem(Int32 i) { if (lbxItems.InvokeRequired) { Action<Int32> a = new Action<int>(addItem); this.BeginInvoke(a, i); } else { lbxItems.Items.Insert(0, i); } }