Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

ProgressWorker

4.22/5 (11 votes)
13 Mar 2009CPOL3 min read 49.7K   1.6K  
A WinForms ProgressBar control with a BackgroundWorker wrapper.

Why?

In many of my projects, I use a background worker for doing background tasks. There are many different scenarios where this is useful. The one thing they all (or nearly all) have in common is that I link it with a progress bar so I can show the user that something is happening.

Even though it's a simple process, I got fed up of typing (or copying/pasting) the same code every time I needed to add this to a project, so I finally got around to combining the two together.

What is it?

So, here is the ProgressWorker. It's nothing amazingly complex, but I've found it useful, so I thought I'd share it with the CodeProject community.

The class derives from System.Windows.Forms.ProgressBar, and is also a wrapper around System.ComponentModel.BackgroundWorker.

What's Different?

You gotta have style!

The standard progress bar has three styles for display. Two show an incrementing bar, and the other (Marquee) shows a bar that 'bounces' from left to right ad infinitum. The latter is most useful for when the progress can't be quantified but you need to indicate that activity is taking place. To make this selection more automated, the Style property now only has Block and Continuous. If, the ReportsProgress property is false, Marquee is selected for the base's Style. The problem with the Marquee style is it keeps going, even when you don't want it to, so this style is only applied when the worker starts working.

There's no limit

The progress bar normally allows you to set your own minimum and maximum values. I've fixed these to 0 and 100 so it plays nice with the worker's ReportProgress, and they're read only.

What's it worth?

The Value property is now read only, as it should only be updated by the worker.

Surplus to requirements

The Step property, PerformStep and Increment methods aren't needed so I've hidden them as best I can.

Inheritance notes

When inheriting from a base class, you are supposed to add functionality, not remove it. Because of this, not everything can be hidden, and will show up in intellisense no matter what attributes you apply. Microsoft say this is intentional and is the correct OOP way #(even though they hide lots of stuff themselves!), but I really didn't fancy having to start from IWin32Window and building everything from scratch.

I've mostly used new instead of override on the things I've changed. Overriding won't, for example, allow you to turn a read/write property into a read only one. So, before anyone attacks me for it, it is intentional!

What's new?

... well, not a lot. The existing control and component have everything needed, this just couples them together into one handy control. Ooh, I have added a Reset method which will set the Value back to zero and stop the Marquee style where applicable.

I've changed a couple of 'wrapped' names to remove the worker reference. Apart from that, you'll find all the normal progress bar and background worker stuff, so it should be very intuitive to use. In case it's not (or you've never used a background worker), there's a demo attached.

Where's the code?

Before I get flamed for writing an article with no code...! There's not really much of interest, as it is (as previously stated) just a derivation of a progress bar with a wrapped background worker. Here's a little code dump of the implementation in the demo's main form to show how easy it is to use:

C#
public partial class FormMain : Form
{
    public FormMain()
    {
        InitializeComponent();
        progressWorker.DoWork += 
          new System.ComponentModel.DoWorkEventHandler(progressWorker_DoWork);
        progressWorker.ProgressChanged += 
          new System.ComponentModel.ProgressChangedEventHandler(
          progressWorker_ProgressChanged);
        progressWorker.RunCompleted += 
          new System.ComponentModel.RunWorkerCompletedEventHandler(
          progressWorker_RunCompleted);
        richTextBox.SelectAll();
    }

    private void progressWorker_DoWork(object sender, 
                 System.ComponentModel.DoWorkEventArgs e)
    {
        for (int i = 1; i <= 100; i++)
        {
            if (progressWorker.CancellationPending)
            {
                e.Cancel = true;
                break;
            }
            // simulate long operation
            System.Threading.Thread.Sleep(50);
            progressWorker.ReportProgress(i);
        }
    }

    private void progressWorker_ProgressChanged(object sender, 
            System.ComponentModel.ProgressChangedEventArgs e)
    {
        Console.WriteLine(e.ProgressPercentage);
    }

    private void progressWorker_RunCompleted(object sender, 
            System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
        button.Text = "&Start ProgressWorker";
        button.Enabled = true;
        progressWorker.Reset();
    }

    private void button_Click(object sender, EventArgs e)
    {
        if (progressWorker.IsBusy)
        {
            button.Enabled = false;
            progressWorker.CancelAsync();
        }
        else // start
        {
            progressWorker.RunAsync();
            button.Text = "&Cancel ProgressWorker";
        }
    }

    private void checkBox_CheckedChanged(object sender, EventArgs e)
    {
        progressWorker.ReportsProgress = checkBox.Checked;
    }
}

References

History

  • 13 March 2009: Initial version.

License

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