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:
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;
}
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
{
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.