
Introduction
One basic limitation of the ProgressBar
control provided by .NET is that it can't show the percentage on top of its rendered background. Given this limitation, I decided to create my own control as an exercise. But System.Windows.Forms.ProgressBar
does not allow extra drawing to be done, so the new control must be created from scratch.
So I created a basic ProgressBar which has the basic properties Minimum
, Maximum
, Value
, and Step
, and an inner function PerformsStep
which advances the Value
appropriatly.
Appearance properties are provided for the aspects of color, border, and the percentage text. TextColorType
specifies whether the text color used is the ForeColor
, or it is automatically generated based on the background color that will be behind it.
Rolling functionality is supported, but it should not be used because it uses a Timer
rather than a thread. It was created for testing purposes only.
Also, based on a tip I read, a custom Dictionary
of Brush
and Pen
is used from the MyComponents.Objects
namespace in order to maintain in memory every Brush
and Pen
used. These Dictionary
s are optional and are automatically disposed.
This base control can be used in Forms, but its drawing is primitive and resembles progress bars of Win3.1.
Rendering is done by the following functions: DrawBackgroundRolling
, DrawBackground
, DrawText
, and DrawBorder
. DrawBackgroundRolling
instead of DrawBackground
is called when rolling is enabled. Any custom progressbar that wants to use the functionality must override the implementation of these functions which are called from the OnPaint
event in the specific order, and only if they are needed, based on the relevant properties.
Custom controls
The first custom progressbar I built was one with a gradient between the color of the progress and the background. Two properties were introduced for this ProgressBarGradient
. PercentageWidth
specifies how much of the control's width will be used for the gradient transition. GradientType
specifies whether PercentageWidth
is 100% or specified.
Here is the code for DrawBackground
:
protected override void DrawBackground(Graphics g)
{
if (_iPercent == 0)
{
FillRectangle(g, ClientRectangle, xBrushes[BrushBackGround]);
}
Rectangle[] xRecs = null;
xRecs = Prepare3Parts();
Rectangle xRectLeft = xRecs[0];
Rectangle xRectMiddle = xRecs[1];
Rectangle xRectRight = xRecs[2];
xRectLeft.Width++;
BrushAndFill(g, xRectMiddle, _ColorProgress, BackColor);
FillRectangle(g, xRectLeft, xBrushes[BrushProgress]);
FillRectangle(g, xRectRight, xBrushes[BrushBackGround]);
}
Prepare3Parts
creates the left, middle, and right rectangles needed to draw the control.
The second custom progressbar is called ProgressBarBoxed
and splits the control to boxes and fills them with the appropriate color relative to the current percent. The properties introduced are:
NumberOfBlocks
specifies the number of blocks to split the progressbar.ActiveBlockColor
specifies the last color of the box if the percentage is between 1 and 99.InnerGridType
specifies the type of grid used to separate the boxes.
Here is the implementation of DrawBackground
:
protected override void DrawBackground(Graphics g)
{
if (_iPercent == 0)
{
FillRectangle(g, ClientRectangle, xBrushes[BrushBackGround]);
}
for (int i = 0; i < _MaxBlockToDraw; i++)
{
FillRectangle(g, _BlockRects[i], xBrushes[BrushProgress]);
}
if(_MaxBlockToDraw<_NumberOfBlocks&&_MaxBlockToDraw>-1)
FillRectangle(g, _BlockRects[_MaxBlockToDraw], xBrushes[BrushActiveBlock]);
DrawInnerGrid(g);
}
Because the appearance of this control doesn't change at every change of Value
, a trick is implemented to speed up the control. The base ProgressBar
provides the functionality by implementing Invalide()
of the control like this:
protected bool _TurnOffInvalidation;
protected new void Invalidate()
{
if (!_TurnOffInvalidation)
base.Invalidate();
_TurnOffInvalidation = false;
}
FormProgressBarsTest
was created to test the three variations of these progress bars and is derived form MyComponents.Windows.BaseForms.PropertyGridForm
which is a form I have created to provide functionality for test forms of controls I create.
Finally, in the Solution, there is project named Functions where I store every function that may be reused in my projects.