Sometimes, a normal control just isn’t enough, or sometimes you may want to extend the already existing functionality of a control; or perhaps, you simply want to make your own control. For all these reasons, I will demonstrate how to create your own Progressbar-like control that exposes the same properties as a normal Progressbar, but with added visual appeal.
What Precisely Is a Component?
To best explain the term Component, let me quote MSDN:
“The term component in the software industry is often used to refer to a reusable object that exposes one or more interfaces to clients in a standardized way. A component may be implemented as a single class, or as a set of classes; the primary requirement is that the basic public interface be well-defined.
“Some of the most commonly used components in .NET Framework programming are the visual controls that you add to Windows Forms such as the Button Control (Windows Forms), ComboBox Control (Windows Forms), and so on. Non-visual components include the Timer Control, SerialPort, and ServiceController, among others.”
Sounds simple enough, so how do you get started? Just follow these steps:
- Fire up Visual Studio .NET 2003.
- Click File, New, Project.
- Select Visual C# Projects from the Project Types list.
- Select Windows Control Library from the Templates list.
- Give a descriptive name, such as GradProg.
- Select OK.
This will produce the design window of a UserControl. This will be the base of your component. This will be your component.
Designing Your Interface
The design is actually quite simple. You don’t need much because you’ll be using the UserControl itself as the Progressbar. All you need to add to the UserControl is one label, and obviously, you need to set some basic properties for both the UserControl and the Label.
Set the following properties for the UserControl:
Property | Value |
---|---|
Name | GradProg |
BackColor | White |
Width | 150 |
Height | 48 |
Add one label to your UserControl (if you haven’t done so already), and set the following properties for the Label:
Property | Value |
---|---|
Name | lblPerc |
AutoSize | True |
BackColor | White |
Text | 0% |
Your design should now look something similar to what’s shown in Figure 1.
Figure 1: The design of your Gradient Progressbar
Coding
Before you jump in and code, you need a plan of action. First, you need to create a Progressbar; in doing that, you need to supply all the needed methods and logic to increment the bar, you will need to implement some Resizing logic, and finally, disposal of your bar. Secondly—this is where the fun comes in—you need to supply your own Properties and Methods to set the various Background Foreground colours, you need to implement the Gradient Style, and you need to make sure your limits (Maximum and Minimum) don’t go out of bounds.
Without further ado, it’s time to get started!
The Needed Namespaces
Open the Code Window for GradProg, and make sure you have the following using statements at the top:
using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms;
These Namespaces are needed mainly for the usage of several Drawing methods you are going to use.
The Needed Variables
You will need to remember your Property values; so, you need to create variables to store their particular values, as well as to set up each Property’s default value.
Add the following variables to your code, just above the Class Constructor:
private int Mini = 0; //Default Minimum Value private int Maxi = 100; //Default Maximum Value private int CurrVal = 0; //Current Value private int Percent = 0; //Percentage //ProgressBar Fore Colour private Color BarForeColour = Color.LightSeaGreen; //ProgressBar Back Colour private Color BarBackColour = Color.DimGray; //Label Fore Colour private Color LabForeColour = Color.LightSeaGreen; //Label Back Colour private Color LabBackColour = Color.DimGray; //Default Gradient Mode private LinearGradientMode GradMode = LinearGradientMode.ForwardDiagonal; private bool DispLabl = true; //Show Label? //Label To Display Progress private System.Windows.Forms.Label lblPerc; private Point LabPos; //Label Position
As you can see with the above code, you have created variables to set up each property; you are going to use the default values. You have variables for the Minimum and Maximum values, the Label’s and Progressbar’s Fore- and Back Colours, the Gradient mode, as well as the Label’s position.
Building the Bar, Block by Block
If you have ever seen how a normal progressbar works, you will understand when I say the bar gets built block by block, until it reaches its limit. With your component, you don’t really need to display blocks; you want a smooth bar. But still, you need to update the display little by little with each increment of your counter. You achieve this with a method named SetProgComplete and the Value property. With each progression of the bar, you need to create a new Rectangle for the display of the bar’s value—not the numbered value, but the graphical value. Create a new method named SetProgComplete, and supply a Integer parameter named percentage; this will act as your incrementation value.
Your method should look like the following:
/// <summary> /// Displays Current Progress /// </summary> /// <param name="percentage"></param> public void SetProgComplete(int percentage) { //Calculate New Width int Width = (int)Math.Floor((this.ClientRectangle.Width * percentage) / 100); //Calculate New Height int Height = (int)this.ClientRectangle.Height; if (Width > 0 && Height > 0) //If Height And Width Valid { //Paint New Rectangle this.Invalidate(new Rectangle(this.ClientRectangle.X, this.ClientRectangle.Y, Width, Height)); //Display Current Progress lblPerc.Text = Percent.ToString() + "%"; } }
The Value Property works hand in hand with your SetProgComplete property. As the bar progresses, a new Rectangle gets created where the previous one ended, thus creating each progression block.
/// <summary> /// Sets Current Value & Updates Display /// </summary> public int Value { get { return CurrVal; //Get Value } set { int OldVal = CurrVal; //Store Previous Value //Keep In Specified Range if ((value < Mini)) { CurrVal = Mini; } else if ((value > Maxi)) { CurrVal = Maxi; } else { CurrVal = value; } //Invalidate Changed Area Only int CurrPercent; Rectangle NewValRect = this.ClientRectangle; Rectangle OldValRect = this.ClientRectangle; //New Value To Calculate New Rectangle CurrPercent = (CurrVal - Mini) / (Maxi - Mini); NewValRect.Width = (NewValRect.Width * CurrPercent); //Old Value For Previous Rectangle CurrPercent = (OldVal - Mini) / (Maxi - Mini); OldValRect.Width = OldValRect.Width * CurrPercent; Rectangle UpdatedRect = new Rectangle(); // Find only the part of the screen that must be updated. if ((NewValRect.Width > OldValRect.Width)) { UpdatedRect.X = OldValRect.Size.Width; UpdatedRect.Width = NewValRect.Width - OldValRect.Width; } else { UpdatedRect.X = NewValRect.Size.Width; UpdatedRect.Width = OldValRect.Width - NewValRect.Width; } UpdatedRect.Height = this.Height; //Repaint Intersection this.Invalidate(UpdatedRect); } }