Programming Examples

Are you a Programmer or Application Developer or a DBA? Take a cup of coffee, sit back and spend few minutes here :)

BackGroundWorker Component & Progress Bar of C#

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

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.

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

  1. Adds the BackgroundWorker Component to the Form.
  2. Sets a name for the component.
  3. 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

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:

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:

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.

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.

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:

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.

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:

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.

9. Events of BackgroundWorker Component

There are three important events of BackgroundWorker that we should handle. In this two are optional. These events are:

  1. DoWork
  2. ProgressChanged
  3. 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

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:

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:

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:

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).

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.

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.

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

  1. The user starts the sample EXE from the explorer.
  2. After the form display, the user clicks the count button.
  3. Clicking on the Window Restore option makes the sample in Not Responding Stage. Because, it is busy with counting vowels.
  4. Clicking the cancel button Fades-out the form (Kind of dead) informing the user that sample is not yet ready and still busy.
  5. 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

  1. We start the sample application.
  2. Then we place a check mark in the Use DoEvents check box.
  3. Clicking the count button shows the Progress Bar Increment and Count Meter updates.
  4. 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

  1. Starts our Example Application.
  2. We select ‘Use Background Worker’ check box and then click Start Count Button.
  3. 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: , , , , ,

Do you like this Example? Please comment about it for others!!

This site uses Akismet to reduce spam. Learn how your comment data is processed.