28 February 2012

Using Background Worker in C#

Most of our application that we develop today require simultaneous functions to perform but with performance.  Working with Microsoft .NET framework we have worked with threads through which we can handle all the tasks simultaneously under one main application thread. You can perform smaller operations with the help of Threading class, instead I prefer using Background Worker class to implement to perform all my heavy duty operations.
Background worker class is introduced in .NET framework 2.0 and using this class makes it easy to execute long running operations on a separate thread, support cancellation, progress reporting and marshalling results back to the UI thread.
Now we will see how to use background worker class to perform heavy operations.
My requirement is execute more than one form code simultaneously. Each form, connect to the database and start the execution back end it takes more than one day. Each form will behave same.  To do this i have choose Back Ground Worker.  
I have four buttons to open four forums when i click each one them, a new window will open and then i will start the execution of functionality.
Now let start working with BackgroundWorker.
Create four forms as shown bellow.

First, you need an instance of BackgroundWorker class,Get to the design mode and drag & drop the background worker component on form,  form Component tab of Toolbox as shown bellow screen.
Set the properties of the background worker:
Set GenerateMember and Modifiers as it is. In the sample application we have a progress bar which reports the percentage of the task completed so we need to set the WorkerReportsProgress to true and similarly if we want the user to cancel the running operation then set the WorkerSupportsCancellation to true.

Now the next step is to create 3 event methods:
1.) DoWork: This is the main method which is responsible to handle the large operation. The code here is not different than the usual code.
2.) ProgressChanged: This method reports the change in the progress of the operation performed by the background worker DoWork method.
3.) RunWorkerCompleted:Thismethod checks the RunWorker Completed Event Args and perform action accordingly.
Starting with the Start button:
Next step is to set the event handlers of you object, and finally you have to call RunWorkerAsync() method.  Whenever you call this method it get a free thread from CLR and fires DoWork event. Now you put your codes (The codes that you want to be executed in another thread) in event handler of DoWork event. If the code completed it will raise an event called RunWorkerCompleted to notify you. It 's important to know that this event is not raised on the new thread instead, it will be raised on main thread of your application.

private void btn_start_Click(object sender, EventArgs e)
{
//Starts the backgroundworker process asynchronously
backgroundWorker1.RunWorkerAsync();
btn_start.Enabled = false;
} 
The DoWork method: 
The event args of DoWork event is an object of type DoWorkEventArgs.
In this object you have a property called Argument for getting what you have passed in RunWorkerAsync() method. You can use it in your time-consuming task. 
//Background worker DoWork method. Here we will perform our heavy duty tasks.
//I have used a simple datareader object to traverse all the rows in the table.
//The table has around 19K rows.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
  try
  {
    int i = 0;
    cmd = new SqlCommand("SELECT * FROM Person.Contact", con);
    con.Open();
    dr = cmd.ExecuteReader();
    while(dr.Read())
    {
        i = i + 1;
        //report to the backgroungworker progreechanged event of the background worker class
        backgroundWorker1.ReportProgress(i);
        Thread.Sleep(1);
        //Called and check if the cancellation of the operation is pending. If returned true
        //DoWorkEventArgs object cancels the operation.
        if (backgroundWorker1.CancellationPending)
        {
            e.Cancel = true;
            return;
        }
    }
   }
   catch (Exception x)
   {
    MessageBox.Show("An error occured while performing operation" + x);
   }
   finally
   {
    con.Close();
   }
}
The RunWorkerCompleted Method:
You may want to have the result of your task in your UI. Again for this purpose you have a property called Result which you can set it in your DoWorkEventArgs. And it will be accessible in your RunWorkerCompletedEventArgs of RunWorkerCompleted event.
private void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled)
    {
        MessageBox.Show("Operation Cancelled");
        btn_start.Enabled = true;
    }
    else
    {
        MessageBox.Show("Operation Completed");
        btn_start.Enabled = true;
    }
}
The ProgressChanged Method:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    //Report porogress bar change
    progress.Value = e.ProgressPercentage;
}
Ending up with the cancel button:
//To cancel async operation
private void btn_cancel_Click(object sender, EventArgs e)
{
     //To cancel the asynchronous operation
     backgroundWorker1.CancelAsync();
     progress.Value = 0;
     btn_start.Enabled = true;
}
So when your application is traversing the records and suddenly you think that you should quit the job and work on other part of the application, just hit the cancel button and the large operation will get cancelled without any freezing and hanging of your application.

Reference Links
4) 

No comments:

Post a Comment