1. Introduction to BackgroundWorker Component
‘BackgroundWorker Component’ is used to do long-running tasks in the background while the application runs in the foreground. When the background task is going on, the application can still look for the user events and replies to them. Generally when the application is busy doing a long-running task, users of the application cannot reach out with the UI items. This is because there is only one thread which is busy dealing with the long-running task.
Here, we will create a sample that counts vowels of the textual content given in a text box. To make that as a long-running task, we will ask the execution to sleep for 50 milliseconds after processing a single character. Using this sample task, we will create our example and study the C# BackgroundWorker Component.
2. About The BackgroundWorker Component Example
The sample created using the Background worker thread is shown below:

C# BackgroundWorker Component Example
When the user clicks the Start Count, the example will count the vowels and displays that in the bottom count meters (i.e.) in the text boxes for A, E, I, O, U. In the meantime, a progress bar will show the progress of the operation. We will intentionally make the counting process slow by using Thread.sleep. The cancel button stops the counting process immediately after pressing it.
When both the check boxes are in the unchecked state and when the sample is counting the vowels, one cannot interact with the form. The ‘Use Doevents’ checkbox will apply doevents API and shows us we can interact with the form. But, when there is an interaction, counting process stops and after interaction completed the counting resumes. To check this, one can use heavy interaction like moving the form or resizing the form. When we progress through this example, we will learn more about doevents API.
The ‘Use Background Worker’ option will overcome the drawback of do only one stuff at once. This means, now with the background worker component, we can see the progress update and change in the vowels counter even when we resize the form. From the downloaded example, one can search for the below tag to get the glimpse of a sequence of code implementation we will do in this example.
Source Code Search Tag: //BWSamp
3. Vowel Count Functions
The below function checks and increments the vowel count for A.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//BWSamp 01: Functions that count and Updates vowel counters. private void CheckVowelA(char c) { long Vowel_count; if (c == 'A' || c == 'a') { if (chkUseBackground.CheckState != CheckState.Checked) { long.TryParse(txtA.Text, out Vowel_count); Vowel_count++; txtA.Text = Vowel_count.ToString(); } else count_a = count_a + 1; } } |
The ‘CheckVowelA’ function checks the passed in value to make sure it is a vowel A. Also note that when the Form is in background thread mode, we just increment a variable count_a. When we are not using the BackgroundWorker Component, the vowel meter for A is incremented and we set the text box for A to this incremented value. We write a similar function for all other four vowels.
At present, you may have a question why we have a separate variable usage count_a for background worker component. We will come to that point later in this article.
4. Adding BackgroundWorker Component
When we know that the form should do a long-running task in the background and in the meantime, the user can still reach out with the form to do some useful work, the BackgroundWorker component is the best choice to deal with such a situation. The video given below shows adding the Background Worker component:
Video Steps
- Adds the BackgroundWorker Component to the Form.
- Sets a name for the component.
- Finally, provides a handler for each three events supported by it.
BackgroundWorker is a component. Hence it does not occupy any space in the form. The ‘Components’ unlike ‘Controls’ don’t have the visual appearance and hence the components sit at the bottom of the form designer when it is dropped in the form. In the video, we handled three events and we will explore those later in this example.
Note that after adding the component we should set two crucial properties called
WorkerReportsProgress
and
WorkerSupportsCancellation
.
WorkerSupportsCancellation
will allow stopping the worker thread in the middle of its task.
WorkerReportsProgress
property is useful to know the progress of the running task. These two properties are below:

Worker Thread Progress Reporting
5. Vowel Counting Variables
We are using
cancel_work
variable to stop the vowel counting work. We use this
cancel_work
variable while in the counting task and when it is not using the ‘BackgroundWorker’ component. The variables
count_a
,
count_e
,
count_I
,
count_o
and
count_u
are used to keep track the vowel counts in the background work mode vowel counting action. Below are declarations:
1 2 3 |
//BWSamp 04: Cancel Action private bool cancel_work = false; long count_a, count_e, count_i, count_o, count_u; |
6. Handler Function of ‘Start Count’
In the start count button handler, we are initializing the vowel-counting variables and then setting the
cancel_work
to false. Based on the
chkUseBackground
checkbox state we start the vowel counting action either in a single threaded or two threaded mode. The call to
DoWithoutBKGrd
function will not use any background thread while doing the count work and the function runs in single thread mode. The call
RunWorkerAsync()
that we make on the BackgroundWorker component (named as BckThread) will call the
DoWork
handler of the same component. At present, we don’t have that handler and will add that in a brief moment. This
DoWork
runs on one thread and all the rest of code runs in a second thread. Below is the code for Start button’s click event handler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//BWSamp 02: Simulate Long Running Task private void btnStart_Click(object sender, EventArgs e) { //2.1: Set Cancel Work as false when the job starts cancel_work = false; count_a = 0; count_e = 0; count_i = 0; count_o = 0; count_u = 0; //2.2: To use back ground worker, call RunWorkerAsync if (chkUseBackground.CheckState != CheckState.Checked) { DoWithoutBKGrd(); } else { BckThread.RunWorkerAsync(); } } |
7. Progress of Counting Operation With DoEvents
In this section, we will implement the
DoWithoutBKGrd
Function. While we explore the code, we will learn how
DoEvents
works and what it lacks on the UI update.
7.1 Variable to Track Progress
From the text box, we are getting the text content into a string variable called
strcontent
and we store its length in the
len
variable. Then we divide the total lengths into 100 parts and store the length of a single part in a variable
Prog_Inc
as initial value to denote 1%. This variable is useful to show the status of the operation accurately in a progress bar (i.e.) If progress bar is in the middle, it stores a value multiple of 50 parts to show 50% of the job completed.
1 2 3 4 |
//3.1: Get text length string strcontent = txtContent.Text; long len = strcontent.Length; int Prog_Inc = (int)(len / 100); |
7.2 Convert Text Box Content to Char Array
As we will count vowels in the set of paragraphs displayed in the big text box, it will be useful to convert all the string content to a char array. The below piece of code is doing just that.
1 2 |
//3.2: Copy the string content to char array char[] chars = strcontent.ToCharArray(); |
7.3 Iterating Char Array For Vowel Count
Once we have text box content in the Char array format, we can examine each of those letters to see whether or not it is a vowel. We are using a loop to iterate through this char array. For each letter, we are making a call to
CheckVowelA-U
. And those functions will do the required stuff (Refer Section 3). Note that in each of the iteration we check the
cancel_work
variable, and when it is set to true, we reset the counter and return. Below is the piece of code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
//3.3: Iterate through each char and increment the Vowels count for (int itr = 0; itr < len; itr++) { if (cancel_work == false) { char c = chars[itr]; lblEvtComplete.Text = "Count In-Progress"; //3.3.1: Count for A CheckVowelA(c); //3.3.2: Count for E CheckVowelE(c); //3.3.3: Count for I CheckVowelI(c); //3.3.4: Count for O CheckVowelO(c); //3.3.5: Count for U CheckVowelU(c); . . . . else { txtA.Text = "0"; txtE.Text = "0"; txtI.Text = "0"; txtO.Text = "0"; txtU.Text = "0"; lblEvtComplete.Text = "Counts Cancelled"; return; } |
7.4 Counting Progress% And DoEvents
The
Prog_Inc
variable holds a value that says when should we do a progress increment of one unit in terms of letters handled till now for vowel counting. If we divide the current progress (the loop counter) by the
Prog_Inc
, we will get the progress%. The variable
prog_value
holds the progress bar% and sets that to the progress bar. The 10 Milliseconds sleeps is to mimic this counting task as long-running task. In this long-running iteration loop, we called the
DoEvents()
Method, when the Use DoEvents checkbox is checked.
1 2 3 4 5 6 7 8 |
//3.4: Update Progress bar int prog_value = (itr / Prog_Inc); if (prog_value > 100) prog_value = 100; ProgressB.Value = prog_value; Thread.Sleep(10); if (chkUseDoevents.CheckState == CheckState.Checked ) Application.DoEvents(); |
The
DoEvents()
function call does not spawn a different thread, and it runs in the same thread. But DoEvent will stop current counting work and does all the pending UI tasks (Say the user resized the form while vowel counting in progress), then returns to the counting operation.
7.5 Disable ‘Use DoEvents’ CheckBox
When we check the check box stating we want to use the background thread for counting the vowels, the ‘use do events’ option gets disabled. The code for this is below:
1 2 3 4 5 6 7 8 9 10 11 |
//BWSamp 06: When using BkGrd component, uncheck and disable doevents private void chkUseBackground_Click(object sender, EventArgs e) { if (chkUseBackground.CheckState == CheckState.Checked) { chkUseDoevents.Enabled = false; chkUseDoevents.CheckState = CheckState.Unchecked; } else chkUseDoevents.Enabled = true; } |
8. Cancelling Counting Task
As Already told, we can cancel the counting task in the middle by clicking the Cancel button. We set the
cancel_work
variable to true and counting task uses this variable to know it needs to abort the task or not. Note, we use this variable when the task is running on the same thread. When the BackgroundWroker component is doing this task, we are making a call to the BackgroundWorker component’s member function
CancelAsync()
to cancel the work. This function call will set the Background Worker component’s
CancellationPending
Property to true. We will check this property in the long-running task.
1 2 3 4 5 6 7 |
//BWSamp 05: Set the Cancel Flag to cancel the current active job private void btnCancel_Click(object sender, EventArgs e) { cancel_work = true; if (chkUseBackground.CheckState == CheckState.Checked) BckThread.CancelAsync(); } |
9. Events of BackgroundWorker Component
There are three important events of BackgroundWorker that we should handle. In this two are optional. These events are:
- DoWork
- ProgressChanged
- RunWorkerCompleted
9.1 DoWork Event & UI Update Issues
The BackgroundWorker fires DoWork event when we call the component’s method RunWorkerAsync(). We can perform the long-running task in the event handler for the DoWork event. This event handler runs on the separate thread and while other two event handlers run on the thread that started this background worker thread. In our case, the form is the main thread that spawns the UI thread by making a call to RunWorkerAsync in the Start Count button click (Refer Section 6).

Interaction Between Main Thread and Worker Thread of BackgroundWorker
In the above picture, the main thread (the form) starts the background thread (sub thread). This sub thread is nothing but the DoWork event handler of the BackroundWorker component. Inside this, changing the UI components of the main thread is not allowed. Say, for example, we want to show the progress of the DoWork in the progress bar. Moreover, we want to update the vowel count meter on the fly. This means we want the update to happen in real-time instead of waiting for the DoWork task to complete. The owner of the progress bar and count meter is the windows form. But we cannot get access to those UI controls of the form from the DoWork handler since it is running in the separate thread. How do we overcome this pitfall?
9.2 ProgressChanged & RunWorkerCompleted Events of BackGroundWorker
The DoWork handler helps the Main thread through the ‘ProgressChanged’ and ‘RunWorkerCompleted’ Event. Note that the worker thread raises these two events and the main thread responds to it. As these two event handlers will run on the main thread, we can do whatever UI updates we like to do. The worker component’s function call ReportProgress will raise the event ‘ProgressChanged’. Once the DoWork handler returns, the event ‘RunWorkerCompleted’ will be raised. Now, we will implement the handlers.
10. Implement DoWork Handler Of BackGroundWorker
Let we dig into the code given in the DoWork handler of the background component.
10.1 Divide String Length to 100 Parts
After getting the length of the entire string content, we divide that string length into 100, so we can inform the progress from 0% to 100%. Below is the piece of code:
1 2 3 4 |
//7.1: Get text length string strcontent = txtContent.Text; long len = strcontent.Length; int Prog_Inc = (int)(len / 100); |
10.2 Vowel Counting
We convert the entire string into a character array, then process the letters one by one to find the letter is a vowel. When it is a vowel, we increment the count meter by one inside the vowel checking functions. Below is the code (almost equal to what we did in section 7) for it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//7.2: Copy the string content to char array char[] chars = strcontent.ToCharArray(); //7.3: Iterate through each char and increment the Vowels count for (int itr = 0; itr < len; itr++) { char c = chars[itr]; . . . //7.3.2: Count for A CheckVowelA(c); //7.3.3: Count for E CheckVowelE(c); //7.3.4: Count for I CheckVowelI(c); //7.3.5: Count for O CheckVowelO(c); //7.3.6: Count for U CheckVowelU(c); |
10.3 Check CancellationPending Property
In the iterations for each letter, we check for the
CancellationPending
Property. This is to to test the Main Thread wants to abort the current work in progress or not. Note that the owner of this DoWork thread can halt this thread anytime by making a call to the
CancelAsync()
Method of the BackgroundWorker component. The above said function call will set the
CancellationPending
Property of the Backgroundworker to true. Remember, we call
CancelAsync
Method in Cancel button handler. When we see there is a cancellation pending, we simply return from the background thread. Below is the piece of code:
1 2 3 4 5 6 |
//7.3.2: Check the Cancel State if (BckThread.CancellationPending == true) { e.Cancel = true; return; } |
10.4 Report Progress to ProgressChanged Event Handler
After processing each letter, we report the progress by making the call to the method
ReportProgress
. This method will fire the event
ProgressChanged
and you know that we already have the handler for that in the form (Not yet implemented). You can refer video 1 towards its end. Prog_inc is 1/100th part of the length of the string and we calculate how much we progressed in the
prog_value
using the
Prog_Inc
. We send this calculated current progress value to the
ReportProgress
function. Even though we cannot change the UI elements from the Background Job thread, we can do the same from the event handler for
ProgressChanged
as this handler runs in main thread (Refer Pic3).
1 2 3 4 5 6 |
//7.4: Update Progress bar int prog_value = (itr / Prog_Inc); if (prog_value > 100) prog_value = 100; BckThread.ReportProgress(prog_value); Thread.Sleep(10); |
11. ProgressChanged Event Handler of BackGroundWorker
The source code of the
ProgressChanged
event handler is straightforward. We get progress percentage through the
ProgressChangedEventArgs
which we get as an argument to the
ProgressChanged
event handler. In the
ProgressChanged
function, we set the progress bar value and in the meantime we also update the vowel count meters based on the values in the class level variables. Remember, we pass Prog_value to the function
BckThread.ReportProgress(prog_value)
, and that value is collected here as an event handler argument.
1 2 3 4 5 6 7 8 9 10 11 |
//BWSamp 08: Handle Progress Changed of Bck Worker Thread private void BckThread_ProgressChanged(object sender, ProgressChangedEventArgs e) { ProgressB.Value = e.ProgressPercentage; txtA.Text = count_a.ToString(); txtE.Text = count_e.ToString(); txtI.Text = count_i.ToString(); txtO.Text = count_o.ToString(); txtU.Text = count_u.ToString(); } |
12. RunworkerCompleted Handler of BackGroundWorker
The code below in the handler for the
<strong>RunWorkerCompleted</strong>
shows setting a label with the notification message to state the BackgroundWorker Component completed the task. The label also reports when the user cancels the task in the middle. There is nothing special that needs to be discussed here.
1 2 3 4 5 6 7 8 9 |
//BWSamp09: Handle Bck Task completed private void BckThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled == true) lblEvtComplete.Text = "Cancelled"; else lblEvtComplete.Text = "Completed"; } |
13. Running the BackGroundWorker Example Application
13.1 Running the Application Without DoEvents and Background Task
First, we will run the example in normal mode. Means we run the sample without BackGroundWorker Component and DoEvent. In the video one can see the user started the counting operation and after that the person resize the form. This keeps the form in Not Responding state, and once the counting operation is completed, the user will get the updated vowel count meter.
Video Steps
- The user starts the sample EXE from the explorer.
- After the form display, the user clicks the count button.
- Clicking on the Window Restore option makes the sample in Not Responding Stage. Because, it is busy with counting vowels.
- Clicking the cancel button Fades-out the form (Kind of dead) informing the user that sample is not yet ready and still busy.
- User waits for the counting to be completed. Once counting task is over, the form comes back to responding stage.
13.2 Running the Application With DoEvents
The above video shows the need for Background work. In the below video we can see the usage of DoEvent. You can notice even though the Progress Bar and Count meter update is smooth, when we move the form for three or four seconds, we can see how the count operation halts and resumes back. The counting meter shows its update when windows completes the move or resize operation of the form. The below video shows a demo of the counting and form move:
Video Steps
- We start the sample application.
- Then we place a check mark in the Use DoEvents check box.
- Clicking the count button shows the Progress Bar Increment and Count Meter updates.
- Resizing the form shows the continuous break in the Progress and Count meter Update till the resize is over.
Somewhat better compared to previous as this time we use the DoEvent on long-running counting operation.
13.3 Running the Application With BackgroundWorker
In this last video, we used the BackgroundWorker component to show how smooth the work of counting and the refresh of Vowel Count Meters. When you resize or move the form, you can see the uninterrupted counting and a progress bar update in the Form UI. This is the power of BackGroundWorker component. What we have here is a simple example that do vowel counting intentionally slow. In the reality, the background worker will do some major task without cutting off the main UI thread. Moreover, the user can still reach out to the form and do some useful application user interface tasks while the work started by him/her is still going on in the background.
Video Steps
- Starts our Example Application.
- We select ‘Use Background Worker’ check box and then click Start Count Button.
- Finally, we Resize the form and change the text box content while vowel counting is busy.
Source Code Download: Download BackGroundWorker Component From Google Drive
Categories: C#
Tags: CancelAsync Function, DoEvents, DoWork Event, ProgressChanged Event, ReportProgress, RunWorkerCompleted Event