Creating a C# Gradient Progressbar Component

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:

  1. Fire up Visual Studio .NET 2003.
  2. Click File, New, Project.
  3. Select Visual C# Projects from the Project Types list.
  4. Select Windows Control Library from the Templates list.
  5. Give a descriptive name, such as GradProg.
  6. 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);
   }
}

Creating a C# Gradient Progressbar Component

The GradientStyle Property

The reasoning behind this property is to enable you to set a certain LinearGradient mode for your Progressbar. As the bar runs, the gradient should be applied. In Design time (once on a test form), you will be able to apply any of the Forward, Backward, ForwardDiagonal, and BackwardDiagonal settings. You create this property simply by adding the following:

/// <summary>
/// GradientStyle Property
/// </summary>
[Description("Sets The Gradient Style"), Category("Appearance")]
public LinearGradientMode GradientStyle
{
   get
   {
      return GradMode;     //Get Value
   }
   set
   {
      GradMode = value;    //Set New Value
   }
}

When this property gets displayed in the Properties Window, it will be placed under the Appearance category. The Description will also be shown in the properties window once this property has been selected.

The Minimum and Maximum Properties

Obviously, this will enable you to set up your Bar's limits. It's not actually as easy as it seems up front. You have to keep in mind that you have limits for a reason. What I'm trying to say is that if, for example, I set my Maximum limit to 1000, I cannot have my Minimum value starting there, and vice versa. You also have to incorporate logic to prevent you from going over or under your established limits. Add the following Behavior properties:

/// <summary>
/// Minimum Property
/// </summary>
[Description("Sets The Minimum Value"), Category("Behavior")]
public int Minimum
{
   get
   {
      return Mini;    //Get Value
   }

   set
   {
      //Is Value Less Than 0?
      if ((value < 0))
      {
         Mini = 0;
      }

      //Is Value Greater Than Max?
      if ((value > Maxi))
      {
         Mini = value;
      }

      //Is Value Still In Range?
      if ((CurrVal < Mini))
      {
         CurrVal = Mini;
      }

      //Repaint
      this.Invalidate();
   }
}

/// <summary>
/// Maximum Property
/// </summary>
[Description("Sets The Maximum Value"), Category("Behavior")]
public int Maximum
{
   get
   {
      return Maxi;    //Get Value
   }

   set
   {
      //Is Value Less Than Min?
      if ((value < Mini))
      {
         Mini = value;    //Store New Min Value
      }

      Maxi = value;       //Continue

      //Is Value Still In Range?
      if ((CurrVal > Maxi))
      {
         CurrVal = Maxi;
      }

      //Repaint
      this.Invalidate();
   }
}

The Percentage Property

This property is used to increment your percentage value; in other words, the bar's numeric value. There's nothing really complicated, as you will see in the next code snippet. Just one thing I also did here was to let the progressbar loop, so, once it reaches the maximum value, it starts over. This is completely optional to do it precisely like I did. I'm just demonstrating where you can manipulate the percentage value. Why? Say, for example, you wanted the gradient to be applied more than only once with each cycle; you could manipulate this property a bit to achieve that. As said, I've decided to use only one cycle, and loop it, mainly because in one of my programs, I've made a Graphic Equalizer that needed to continue the looping process; but, that is a different program. Rather, you should get back to writing the Percentage property, before I get way off topic. [_Smiley.gif] Now, add this Configuration property:

/// <summary>
/// Percentage Property
/// </summary>
[Description("Sets Current Percentage Value"),
   Category("Configurations")]
public int Percentage
{
   get
   {
      return Percent;    //Get Value
   }

   set
   {
      Percent = Percent + value;    //Increment

      //Looping?
      if (Percent > Maxi)
      {
         Percent = 0;          //Start Over Then

         this.Invalidate();    //Repaint
      }
   }
}

Background and Foreground Colours

When dealing with Gradients, you have to remember that you are dealing with two colours, the starting and colours, if you may. So, the plan of action here is to have a background colour "morph" into a foreground colour gradually. The Label's and the Bar's colours can be different, but it actually works best if both are the same. It basically gives the label a transparent effect. You create the Background and Foreground colours for the bar and the label like so:

/// <summary>
/// ProgressBar's Fore Colour
/// </summary>
[Description("Sets The Bar Fore Colour"), Category("Appearance")]
public Color ProgressBarForeColour
{
   get
   {
      return BarForeColour;     //Get Value
   }

   set
   {
      BarForeColour = value;    //Set Value

      //Repaint.
      this.Invalidate();
   }
}

/// <summary>
/// ProgressBar's Back Colour
/// </summary>
[Description("Sets The Bar Back Colour"), Category("Appearance")]
public Color ProgressBarBackColour
{
   get
   {
      return BarBackColour;      //Get Value
   }

   set
   {
      BarBackColour = value;    //Set Value

      //Repaint.
      this.Invalidate();
   }
}

/// <summary>
/// Label's Fore Colour
/// </summary>
[Description("Sets The Label Fore Colour"), Category("Appearance")]
public Color LabelForeColour
{
   get
   {
      return LabForeColour;     //Get Value
   }

   set
   {
      LabForeColour = value;    //Set Value

      //Repaint.
      lblPerc.ForeColor = LabForeColour;
   }
}

/// <summary>
/// Label's Back Colour
/// </summary>
[Description("Sets The Label Back Colour"), Category("Appearance")]
public Color LabelBackColour
{
   get
   {
      return LabBackColour;     //Get Value
   }

   set
   {
      LabBackColour = value;    //Set Value

      //Repaint.
      lblPerc.BackColor = LabBackColour;
   }
}

The ShowLabel Property

You may choose to have a visible numeric clue as to the particular progression value, or not; you create this "decision" as shown with the following code snippet:

/// <summary>
/// Shows Or Hides Label
/// </summary>
[Description("Shows Or Hides The Label"), Category("Behavior")]
public bool ShowLabel
{
   get
   {
      return DispLabl;     //Get Value
   }

   set
   {
      DispLabl = value;    //Set Value

      //Apply Property Value
      lblPerc.Visible = DispLabl;
   }
}

The LabelPosition Property

This property is used to set the location of your label. Add the following code:

/// <summary>
/// Sets Label's Location
/// </summary>
[Description("Sets The Label Position"), Category("Appearance")]
public Point LabelPosition
{
   get
   {
      return LabPos;     //Get Value
   }

   set
   {
      LabPos = value;    //Set Value

      //Apply Property Value
      lblPerc.Location = LabPos;

      //Repaint
      this.Invalidate();
   }
}

Tying Up Loose Ends

All you still need to do with your component is to include Resize and Paint events. With the Resize event, I simply Invalidate the control's display; with the Paint event, I set up the Gradient brush you are using. Add these two events:

/// <summary>
/// Repaints When Resized
/// </summary>
/// <param name="e"></param>
protected override void OnResize(EventArgs e)
{
   // Repaint Control
   this.Invalidate();
}

/// <summary>
/// Apply The Gradient Effect
/// </summary>
/// <param name="e"></param>
protected override void OnPaint(PaintEventArgs e)
{
   if (e.ClipRectangle.Width > 0)    //If Valid Rectangle
   {
      //Create Gradient Effect In Specified Rectangle,
      //With Specified Colors
      LinearGradientBrush GradBack = new
         LinearGradientBrush(e.ClipRectangle, BarBackColour,
         BarForeColour, LinearGradientMode.BackwardDiagonal);

      //Paint It
      e.Graphics.FillRectangle(GradBack, e.ClipRectangle);
   }
}

Disposal of Your Component

You need to make sure that all resources are released:

/// <summary>
/// Clean Up Resources
/// </summary>
protected override void Dispose( bool disposing )
{
   if( disposing )
   {
      if( components != null )
         components.Dispose();
   }
   base.Dispose( disposing );
}

Creating a C# Gradient Progressbar Component

Okay, I Lied

The absolute final thing you need to do with GradProg is to make sure that when you resize your component, or move it around, or EVEN use it, that you avoid the flickering. Flickering isn't pretty, and not professional. Flickering needs to be stopped at all costs! How ...?

Just add the following line inside your Constructor after the call to InitializeComponent:

//Prevent Flickering, This Produces Smooth Progression
SetStyle(ControlStyles.AllPaintingInWmPaint |
   ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);

Your entire Constructor needs to look like the following:

public GradProg()
{
   // This call is required by the Windows.Forms Form Designer.
   InitializeComponent();

   //Prevent Flickering, This Produces Smooth Progression
   SetStyle(ControlStyles.AllPaintingInWmPaint |
      ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);

}

This prevents any kind of flickering when updating the graphical display.

You can now build your Component by selecting Build Solution from the Build menu. Do not attempt to run it; it will not work. You need to add this component to a Standard Windows Project first!

You can now select either File, Add Project, New Project (to add the test project to the same solution), or Close this current solution, and start a new solution from scratch. Whichever option you choose, make sure to select Windows Application for your testing. I've opted, rather, to create a separate solution. Once your Design view is active, you need to add your created component to your Toolbox. To add GradProg to your Toolbox, follow these steps:

  1. Right Click on the Toolbox.
  2. Select Add / Remove Items....
  3. Select Browse on the .NET Framework Components tab.
  4. Browse to the directory containing GradProg.dll; you should find it in the Debug directory.
  5. Select it.
  6. Click OK.
  7. Select GradProg from the Toolbox, and add it to your form.

Simple, wasn't it?

After you have added GradProg to your test form, you will have a form similar to Figure 2.

[TestFormDesign.jpg]

Figure 2: The Gradient Progressbar after it has been added to a form

Testing GradProg's Properties

If you were to open the Properties Window now, you should have a display similar to Figure 3.

[ComponentPropsInPropWin.jpg]

Figure 3: The Gradient Progressbar's new Properties

You now can play around with all these properties you've created, or, you could set them at run time.

Setting Runtime Properties

For your component to work, you need to add a Timer to your test form as well. Name the Timer control tmrTest. In tmrTest's Tick method, you need to call your Gradient Progressbar's SetProgComplete method to do what it has to. Before you do that, start at the beginning—and that is to set a variable holding your incrementation value:

private int PercComplete = 10;    //How Much At A Time?

Your ProgressBar will be updated by 10 at a time. If you can recall, you created a Percentage property, and in the Timer's Tick event you will also set this property.

The next step is to modify your Form's Load method to initialize the Timer, and you obviously can set the Gradient ProgressBar's other properties here as well. My Form_Load looks like this:

/// <summary>
/// Set Startup Values For Gradient ProgressBar Component
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void frmTest_Load(object sender, System.EventArgs e)
{
   gptest.Percentage = 1;    //Set Progression Value
   //Set Startup Colour In Code
   gptest.ProgressBarBackColour = Color.Orange;
   //Set Startup Colour In Code
   gptest.ProgressBarForeColour = Color.White;

   //Set Startup Colour In Code
   gptest.LabelBackColour = Color.Blue;
   //Set Startup Colour In Code
   gptest.LabelForeColour = Color.White;

   gptest.ShowLabel = true;    //Show The Label

   //Define Gradient Style
   gptest.GradientStyle =
      System.Drawing.Drawing2D.LinearGradientMode.Vertical;

   tmrTest.Interval = 100;    //Timer Interval
   tmrTest.Enabled = true;    //Enable Timer
}

And my tmrTest_Tick looks like the following:

   /// <summary>
   /// The Actual Progression Of The Bar
   /// </summary>
   /// <param name="sender"></param>
   /// <param name="e"></param>
   private void tmrTest_Tick(object sender, System.EventArgs e)
   {
      gptest.Percentage = PercComplete;             //Set Next Value
      gptest.SetProgComplete(gptest.Percentage);    //Apply!
   }
}

Once run, your GradienProgressBar should look similar to Figure 4.

[RunTime.jpg]

Figure 4: The Gradient Progressbar in action

Included with this article is the Component's source code, as well as the Test Project's source code.

Conclusion

I sincerely hope that you have enjoyed this demonstration as much as I did, and I also hope that you now realize how easy it is to create your own component for your own needs. Until next time, happy coding!



About the Author

Hannes du Preez

Hannes du Preez is a Microsoft MVP for Visual Basic. He is a trainer at a South African-based company. He is the co-founder of hmsmp.co.za, a community for South African developers.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds