Click here to Skip to main content
15,884,836 members
Articles / Programming Languages / C#

Working with BackgroundWorker & Creating Your Own Loading Class

Rate me:
Please Sign up or sign in to vote.
4.46/5 (19 votes)
5 Mar 2009CPOL4 min read 79.3K   4.2K   70   9
Basic knowledge about BackgroundWorker. Using BackgroundWorker to create a loading form to inform the user that the application is still working fine. From that, create your own loading class to automate this progress and make the code and the form reusable.

Background

It's always annoying when I run an application, click a button and the whole application becomes frozen. You don't know whether it has crashed or it is still working. Try to click on any other button, we will get the message "Not responding" or something like that.

image01.jpg

That does not sound like a modern application, doesn't it. So don't make your application like that. Whenever your application starts to run a big slow method, make sure you inform your user about that.

Using the Code

BackgroundWorker is there to help you solve this problem. With this, you don't need to worry about how Asynchronous methods work. To inform users that your application is running, create a Loading Form, run the BackgroundWorker, show up the Loading Form. Whenever the backgroundworker is completed, close the form.

image02.jpg

Simple right? But I want more. For me, reusable is also important. I need to use Loading Form in different applications, different form. I can't be asked to create a backgroundworker for every form, every function for which I need it.

So I also create my own Class/Library to make my life easier. This class will auto-create a backgroundworker, run the code, show the form, and close the form when it finishes. This is one of my favorite classes in my Utilities Belt Library. (I have my utilities class which I use for almost every project that I am working on, can't live without it.)

If you don't know about the basic BackgroundWorker, you should read the "Basic BackgroundWorker" part. If you just want to know more about how I create my class, scroll down to the "Make your own class" part.

Basic BackgroundWorker

BackgroundWorker is a simple (simplest maybe) way to make your app run multi-threading. To using it:

Insert a new BackgroundWorker into your form.

Insert your function into DoWork event.

C#
private void bWorker1_DoWork(object sender, DoWorkEventArgs e)  
{  
    decimal ThisMaxValue = Maximum;  
    if(e.Argument!=null && e.Argument is decimal)  
        ThisMaxValue = (decimal)e.Argument;  
    //This is run in a new thread  
    for (int i = 0; i <= ThisMaxValue; i++)  
    {  
        Idx = i;  
    }  
}

[Optional] Insert some command into RunWorkerCompleted if needed.

C#
private void bWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)  
{  
    nudShowResult.Value = Idx;  
    timer1.Stop();  
    if (LoadingForm != null && LoadingForm.Visible)  
        LoadingForm.Dispose();  
}

Start running BackgroundWorker.

C#
private void button4_Click(object sender, EventArgs e)   
{   
    timer1.Start();   
    bWorker1.RunWorkerAsync();   
    LoadingForm = new FrmLoading();   
    LoadingForm.ShowDialog();   
}

Make sure to show the form after running the backgroundworker. If not, the backgroundworker won't run ask if it needs to wait for the form to close first.

Create a timer if you need to update the value into a control:

C#
private void timer1_Tick(object sender, EventArgs e)   
{   
    nudShowResult.Value = Idx;   
}

The function in BackgroundWorker is not allowed to access any controls because it is in a different thread. If it fails to do so, you will get a really slow error report. So make sure you don't point to any control in the DoWork event.

To run BackgroundWorker function with an argument, you could do like this:

C#
bWorker1.RunWorkerAsync(decimal.Parse(textBox1.Text));

Then extract the argument from eventArgs:

C#
if(e.Argument!=null && e.Argument is decimal)   
    ThisMaxValue = (decimal)e.Argument;

You could check my code file for more details if necessary.

Make your Own Class

This class isn't exactly what in my Utilities belts class. This is made for the purpose of this tutorial only.

So what we need:

Create a new Library project and add System.Windows.Form into your project references.

Add those using into your class file:

C#
using System.Windows.Forms;   
using System.ComponentModel;

Add a new form for loading form. It will show up every time the BackgroundWorker starts and close when it finishes.

Declare a delegate void. Use this to pass a function into your class:

C#
public BackgroundWorker Bw;   
public delegate void RunFunction();

Add some variables for the class:

C#
public BackgroundWorker Bw;   
public RunFunction thisFunction;   
LoadingForm newLoading;

The construction will be like this:

C#
public BackgroundLoading(RunFunction newFunction)   
{   
    thisFunction = newFunction;   
    Bw = new BackgroundWorker();   
    Bw.DoWork += new DoWorkEventHandler(Bw_DoWork);   
    Bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Bw_RunWorkerCompleted);
}

newFunction is what will run in DoWork event. Create a new BackgroundWork and add an event handler for it.

The basic simple code for those event handlers is:

C#
void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)   
{   
    newLoading.Dispose();   
    MessageBox.Show("Complete");   
}   
  
void Bw_DoWork(object sender, DoWorkEventArgs e)   
{   
    if (thisFunction != null)   
        thisFunction();   
}

Add a start function, which will run the BackgroundWorker and show up the loading form.

C#
public void Start()   
{   
    Bw.RunWorkerAsync();   
    newLoading = new LoadingForm();   
    newLoading.ShowDialog();   
}

That's it for the simple loading class.

Using this Class

Add a method, this will run asynchronously.

C#
public void Counter()   
{   
    for (int i = 0; i <= Maximum; i++)   
    {   
        Idx = i;   
    }   
}

Create a new class and associate the new method with this class. Then run the class by using its Start method.

C#
private void button5_Click(object sender, EventArgs e)   
{   
    LoadingClass.BackgroundLoading BL = new LoadingClass.BackgroundLoading(Counter);   
    BL.Start();   
}

That's it! You could try the code examples to see how it really works.

Points of Interest

BackgroundWorker is a great control which help us to run multi-threads much easier. Using it effectively could make your app much more professional and user friendly.

As I only try to cover a basic approach to BackgroundWorker, the class was just a simple example. There is a lot of room for improvement. You could add a timer to see how long it runs, or add a GIF animation to make it look cool?

History

  • 5th March, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Freelance
Vietnam Vietnam
After the success with my personal website hieu.co.uk(about Software dev and web dev), I decide to port some of my tutorial to CodeProject as I think it would be useful.

My main purpose is to share my experience, learn more from community and make more friend ^o^.

Comments and Discussions

 
GeneralMy vote of 5 Pin
RupaliPawar3-Oct-10 20:29
RupaliPawar3-Oct-10 20:29 
GeneralGood basic article Pin
Donsw24-Mar-09 10:51
Donsw24-Mar-09 10:51 
QuestionNice article Pin
Khayralla10-Mar-09 17:32
Khayralla10-Mar-09 17:32 
GeneralAnother option with a bit less copy and paste each time you use it Pin
Paul B.10-Mar-09 10:10
Paul B.10-Mar-09 10:10 
QuestionBackground worker or new thread? Pin
supercat96-Mar-09 5:27
supercat96-Mar-09 5:27 
I've sometimes used similar code when necessary to show a 'busy' form with progress bar. I'd be a little leery of using a BackgroundWorker in that context, though. The BackgroundWorker is designed to use a thread pool on the assumption that if too many pieces of work remain to be done it's better to run them sequentially than in parallel. If the "background work" is stuff that doesn't need to be done in any particular time frame, that's fine, but if some classes' initializers happen to create background jobs that will take awhile to complete, the initialization necessary to begin the application may be postponed.

That having been said, my present coding style is to have a UI thread and a "do things" thread. When the UI thread wants something to happen, it passes a delegate to the "do things" thread. If the "do things" thread gets stuck on something, there are some ways the UI thread can try to ask it to finish up. In some cases (e.g. the "do things" thread gets stuck in unmanaged code) it may not be possible to revive the application, but at least the UI will remain responsive and can inform the user of what's happening.
GeneralMy vote of 2 Pin
marco_br6-Mar-09 5:18
marco_br6-Mar-09 5:18 
GeneralRe: My vote of 2 Pin
hieuuk6-Mar-09 5:57
hieuuk6-Mar-09 5:57 
GeneralAn example project would be nice Pin
Steve Messer6-Mar-09 4:41
Steve Messer6-Mar-09 4:41 
AnswerRe: An example project would be nice Pin
hieuuk6-Mar-09 5:50
hieuuk6-Mar-09 5:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.