During the coding and testing of an application for one of my clients, I ran over and over against the wall using the .NET progressbar control. I missed a lot of properties to adjust the progressbar to the design of my application instead of the default Windows look ‘n feel. Properties like a smooth indicator, printing the progress inside the control and more control over the colors of both the background and the progressbar. After searching CodeProject, I’ve found some nice contributions, but none fitted my requirements. That’s why I wrote my own. My first concern was the replacement of the existing progressbars in my application. Changing them to another progressbar should be as easy as change the declaration and initialization from
private System.Windows.Forms.ProgressBar progressBar = new System.Windows.Forms.ProgressBar();
to
private ExtControls.ExtProgressBar progressBar = new ExtControls.ExtProgressBar();
To reach that goal, I wanted my control to inherit from the .NET progressbar. Unfortunately, Microsoft decided, in all it’s wisdom, that the ProgressBar control should become a sealed class. Therefor, I had to create a new control from scratch, which implemented every property and every function of the original .NET progressbar.
![]()
What does it do?
As you should have guessed by now, the control is capable of drawing a progressbar in a lot of different ways. On the right is a screenshot with some of the possibilities of the control.
Features
- A smooth progressbar, as seen in the first progressbar in the screenshot.
- A label inside the progressbar, which uses String.Format to insert the progress in percentages, the actual progress value, the minimum value and the maximum value.
- You can define two colors for the text label. One color will be used for the text which is printed inside the progressbar, the other for text which is outside the progressbar.
- You can choose from three different brushes: the TextureBrush (progressbar #6 and #9), the GradientBrush (progressbar #2, #4, #5 and #7) and the HatchBrush (progressbar #4 and #5).
- You can define the block size and the gap width (progressbar #2 and #3).
- Gridlines can be printed inside the progressbar (progressbar #8). You have control over the alignment (top, middle and bottom) as well as over the heights, widths and spacing.
- You can define a horizontal or a vertical progressbar (progressbar #5, #9 and #10 are vertical oriented) and two different directions (progressbar #3 is drawn with a right to left direction).
- Label can freely rotate (progressbar #9)
Using the control in your code
The ExtProgressBar control inherits from the Control class. Using it should be as easy as adding a reference to the ExtControls assembly or adding the source files to your own project. After compiling your project, the ExtProgressBar control should show up in your toolbox.
The code
One of the most annoying things of the .NET progressbar is the flickering when the bar is repainted. The solution is simple, and SetStyle is the answer. I won’t go into details here, since there are a lot of articles out there which can explain the usage and working of the following SetStyle call a lot better then I can.
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer | ControlStyles.SupportsTransparentBackColor, true);
These four ControlStyles allow me to paint the control completely trough my own code, flickerfree and with a transparent background.
The properties
When creating a control which can be used from the toolbox and which has a lot of settings, you’ll going to need the Properties Window. Therefor, I wanted all the properties to make use of that usefull window. Since my control only uses simple types (like integers, floats, strings, structures and enumerations) we can just use some Attributes here. Typing
[Description("The size of the control in pixels"), Editor("Size", typeof(UITypeEditor)), DefaultValue(typeof(Size), "100, 23")]
above a property was enough to let the property show up in the Properties Window. All properties with the above Attributes defined, will show up in the category "Misc". If that’s not what you want, add a CategoryAttribute, like this:
[Category("Layout")]
Drawing the control
To draw the control, one could choose between two different approaches. You can attach a delegate to the OnPaint handler, or override the OnPaint method from the Control class. The latter is preferred, because calling a function trough a delegate is generally a little bit slower then calling a overridden one.
protected override void OnPaint(PaintEventArgs e) { ... }
In this function, we draw the control in five steps:
- Draw the background
- Draw the progress indicator
- Draw the gridlines
- Draw the label
- Draw the borders
Drawing the background and progress indicator
Drawing the background can be done in a few different ways. We can override the OnPaintBackground method, or draw the background in the OnPaint functions. In this case, we draw the background in the OnPaint function, as we’ve specified earlier using the SetStyle call (AllPaintingInWmPaint). Drawing the background itselft is no high tech programming. In fact, creating a brush and filling a rectangle is all there is to it.
Brush brush = GetBrush(...); g.FillRectangle(brush, g.VisibleClipBounds); brush.Dispose();
The GetBrush function creates a brush based on the arguments given. The arguments are filled by the properties set at design time. The GetBrush function is used to create all brushes in the control. Check the code if you want to see what it does exactly, but it’s nothing more then a few switches and if statements. We call the Dispose method manually when we don’t need the brush anymore, because we wan’t to free the unmanaged GDI resources immediately. Download demo project ~ 16 kB Download source code (control + demo project) ~ 19 kB
Thanks to
- James T. Johnson for his article Image Rotation in .NET.
- Bob Powell’s GDI+ FAQ.
- Steve Medley for notifyng me of the incorrect version on this website.
I just needed a progress bar that displays text. Harder said than done it seems. Thanks for this invaluable control.
Easier said than done >.>
Nice control. these are the sort of features the progressbar should have. I am curious though how you orient them vertically. I downloaded the source code but cannot find a property to do that. could you please give me a lead on how to achieve this. Thanks