Tuesday, January 27, 2009

Creating Custom Controls In C#.net

Creating Custom Controls In C#.net

When I began programming Windows programs, the programs I wrote were very simple. Place a button on a form, put a label next to it, do some calculations and output some results. When I learned how to access databases, and how to manipulate data sources and run queries, my programs still were fairly simple and used only prepackaged controls.

However, there came a time when I wanted to delve into the inner workings of these controls, and even to make my own from scratch. Maybe the existing controls don’t look or act the way I need them to, and sometimes it’s just for organization purposes. Whatever the reason, there will come a time when a custom control is the necessary component.

In previous environments, programming custom controls was a fairly difficult task that involved loading in obscure libraries and writing code that looked horribly out of place when compared to the rest of a program.

The .Net framework greatly simplifies this problem. Controls are fairly easy to create, and the necessary libraries and their interfaces fit perfectly with the rest of the program code. It is that process which I intend to teach you in this tutorial. Not only are you going to learn how to create a custom control that has its own paint method, but you will also learn how to place that control into a distributable DLL file, and link it into another project.

What You Will Need

In order to follow this tutorial you will need to have Visual Studio 2005 or Visual Studio 2008 installed. I personally use the Express Edition of Visual Studio, which is free. You can also use SharpDevelop, which is a free C# compiler and development environment. Though SharpDevelop is very similar to VS, there are slight differences that I will not go over in this article. It has a very intuitive interface, however, so there should be no problems.

Let's Get Started

Follow these steps to begin creating our custom control.

  1. Open Microsoft Visual C#, and click on the File menu. Select "New Project."
  2. We want to create a "Windows Forms Application," so select that entry.
  3. You can name the project whatever you wish, I will call mine "CustomProgressBar."
  4. Click OK to continue.

You will be presented with a new windows application project.






























This is the default setup of a basic Windows Forms application. What you see here is a single form, or window, called Form1. On these forms you place controls such as buttons, textboxes, images, and labels. What we are going to be placing on this form, later, is our own custom progress bar control.

Our DLL Subproject

We can’t do too much with this form just yet. Our next step is to create a subproject from this main programming project. This new project will be a DLL project that will contain our custom progress bar control.

  1. To create a DLL subproject, Right-Click on the Solution Explorer entry for "CustomProgressBar." It is the top-level entry in the solution explorer, which is shown at the top right of the image above.
  2. Choose Add, and then click "New Project."
  3. Select "Class Library" and name the project "ProgressBar". A class library project will compile into a .net DLL file that can be imported into other projects. Inside of this DLL will be our custom progress bar control
  4. Click OK to Continue.
Now that we have our new project created, we must link the windows form application and the class library together. This is done by creating a "reference" inside of the windows form application.

Follow these instructions to reference the DLL file to our windows application.
  1. Under "CustomProgressBar" in the solution explorer, right-click on References and select "Add Reference."
  2. Change the top tab to "Projects" and select the ProgressBar project.
  3. Click OK.

You have now successfully linked the two projects together.

A Little Background

Now that we have our DLL project set up, let’s go into some background of how this control functions as well as all other windows controls.

In Windows programming, a “form” is what is physically displayed as a window. These forms contain multiple “controls,” such as buttons and textboxes. In order for the user to interact with these controls, they accept and handle “events.” An event is any important occurrence that the control is interested in handling.

One example of an event occurrence is when the user of the program clicks a button on a form. When the click occurs, an event is generated by the operating system that is sent to the form program. The program code of the window contains “event handlers” which are meant to process this message. The form will then try to process the event that was sent to it, but since the user clicked on a button inside the form and not the window itself, the event will be sent by the form to the proper event handler contained within the button’s program code. In this instance, it would be the “OnClick” event handler of the button control.

In order to create a custom control, you must first create a UserControl object that gives you a blank window to work with, much like a form but without the overhead of being a window. You then program custom event handler to handle any kind of event you are interested in. These events could be mouse clicks, having the user press the key, or other non-user events such as a redrawing of the screen.

In this tutorial, the only event our control will be interested in is the screen redrawing event, called OnPaint. This is because the control will be drawing the progress indicator on the screen manually.

Creating The Custom Control


This brings us to the business of creating the custom control object. The last step we took was to create a DLL subproject inside our main project. When that subproject was created, it brought along with it a file “Class1.cs” which we will not need.
  1. In the Solution Explorer, right-click on Class1.cs and delete it.


Now that the default code file is gone, we can create our new custom control.

  1. Once again in the Solution Explorer, right-click on the ProgressBar project and go the Add submenu.
  2. Select “User Control.”



Name the new control “ProgressControl” and select OK. By creating the object in this way, Visual Studio has set us up with all the default files necessary to begin creating our user control which we named ProgressControl. You should be presented with a window like this one.


As you can see, we have a blank panel in the design view that we can add controls to. This is how custom controls work. You begin with a blank panel, and then you can either add other controls to the panel, or you can use Windows GDI programming to draw your own graphics onto that control. Since we are going to be drawing our own progress bar, we will use GDI+ to draw directly to this panel.

Setting Up The ProgressBar Panel

Now that we have our progress bar panel created, we need to set up the default options for the appearance of the panel. Select the panel in the middle by clicking on it. On the right side of the screen, you should see a “Properties” window.

Change the following properties for the ProgressControl:
  1. BackColor: Window
  2. BorderStyle: FixedSingle
  3. Size: 148, 14
  4. Double-Buffered: True
The BackColor property determines the color of the progress bar’s background. Here we set that to one of the predetermined Windows colors, Window. I recommend that you use these predetermined colors in most of your custom controls, because they are based off of the theme that the user who runs your program has set.

The FixedSingle property for the border will create a single black line that goes around the perimeter of the panel. That is how the border of most progress bars look, and it will define the

DoubleBuffering is very important for this control. Because we will be manually drawing the Progress Bar, updating it many times per second could cause problems. In fact, it will “flicker” when the bar redraws itself. By turning on the double buffering, Windows will swap between two copies of the image, first drawing the bar in memory and then displaying it to the screen. This will eliminate any flickering on the object.

After settings these properties, the window for our progress bar should be set up and ready to go. Your progress bar panel should now look something like this:


How About Some Code?

Here’s the good news: our projects and their components are now set up and we are ready to begin some actual programming! So far through this tutorial it has been a matter of setting up projects and setting configuration options in the visual editor. Now, however, we are going to start writing some actual code.

I have good news. The code to create a custom progress bar is very simple! All we are going to create are a few properties and some event-overriding functions.

From the window pictured above, where you see the ProgressControl panel, click on View…Code, or just press F7. You will be presented with the code file that controls the ProgressControl.

You will see in this code file the following class:

public partial class ProgressControl : UserControl
{
public ProgressControl()
{
InitializeComponent();
}

}

Notice that the ProgressControl is initialized by code very similar to a form element. If you pull up the code file for the Form1 object in this project, you will notice that the constructor for the class also just calls the InitializeComponent() function. That function comes from the UserControl parent class, and prepares the control for the form.

The colors on our ProgressBar will be configurable from code. The BackColor property from the UserControl class will take care of the background color for our control, but we need to allow the programmer to choose a foreground color, which will be the color of our progress bar.

Add the following code to the ProgressControl, under the ProgressControl() constructor:

protected Color barcolor = SystemColors.Highlight;

public override Color ForeColor
{
get {
return barcolor;
}
set {
barcolor = value;
this.Invalidate();
}

}

Above is the code that will allow the programmer to set the foreground color of the progress bar. Notice that the barcolor variable itself is protected. Because it is protected, the programmers who use this control from the outside will be forced to set its value through the ForeColor property.

This is an override function because the ForeColor property already exists in the UserControl class. The entire reason for overriding the ForeColor property is the single line “this.Invalidate().”

The Invalidate() function causes Windows to mark the control as “dirty,” meaning it needs to be redrawn. When we change the color of the progress bar, we want Windows to immediately redraw the bar with the new color. That is what the Invalidate function and therefore the ForeColor property will do for us.

Now let’s create another property that’s a little more complicated, but not much. The programmer is going to need the ability to set the percentage that the progress bar should display. We will only work with percentages with our progress bar. There will be no minimum or maximum values, only a percentage of completion in the range 0% to 100%.

Let’s create a property called Value that lets the programmer set the current percentage of completion for the progress bar. Place the following code below the ForeGround property of the ProgressControl class.

protected float percent = 0.0f;
public float Value
{
get {
return percent;
}
set {
// constrain value to between
// 0 and 100
if
(value < style="color: blue;">value = 0;
if (value > 100) value = 100;
percent = value;
this.Invalidate();
}

}

Above is the property, Value, that lets the programmer set the current percentage mark of the progress bar. If the Value property is set to 50, then the progress bar will be 50% full.

The value that can be assigned to the property is constrained in the set portion to be between 0 and 100. This is just to avoid any possible problems in the future that could arise from allowing programmers to set negative percentages, or percentages above 100. It only makes sense for a progress bar to display progress from 0% to 100%.

Once again, this property invokes the Invalidate() method. When the current progress being displayed is changed by the programmer, we want the progress bar to immediately re-draw itself.

Drawing The Progress Bar


There is only one function left! Isn’t that amazing? I hope you are beginning to see that it’s not so difficult to create a custom control with the .Net framework.

The function that remains is the one that actually draws the progress bar on the panel that is the background for the control. The code does exactly what it sounds like it does, there is no magic. We are simply going to draw a rectangle directly onto the panel that will fill in the desired percentage of the panel with the assigned ForeColor. That’s it.

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Brush b = new SolidBrush(barcolor);

// calculate width of progress bar filler in pixels
int width = (int)(((percent / 100) * this.Width));

// draw the progress bar
e.Graphics.FillRectangle(b, 0, 0, width, this.Height);

b.Dispose();

}

The above is the last function we need for our progress bar. It is the OnPaint() event method. This function is automatically called by Windows when the progress bar needs to draw itself. As you can remember from above, we would force the progress bar to redraw itself at times using the Invalidate() method. This function is called as a result.
Let’s start from the beginning. This function is an “override” function because it is meant to be called instead of the base method OnPaint() that comes from the UserControl class, which our progress bar derives from. The function receives an object called “PaintEventArgs” which controls another object “Graphics” that will let us draw on the control.

The first line will call the base.OnPaint() method. This means we first want the control to go ahead and draw itself and handle the event of painting by using its own normal method. In the case of this control, it is alright to leave that line out because the control is very basic. For more advanced controls with multiple levels of inheritance, you may want the underlying control to draw itself first. It’s a good idea to leave that line unless you know you don’t want it.

The next line of code will create a “SolidBrush” object. When windows draws to the screen, it uses objects called Brushes. These brushes define the colors that will be used for the drawing. There are many built-in brushes that can be used, but since we want the color of the bar to be configurable, we create a new SolidBrush using the selected forecolor.

The next line is probably the most difficult line in the entire program. It seems that programmers have a very hard time getting away from math. That is true in GUI programming because you have to be very precise with the length of width of what you are drawing so it will look correct on the screen.

We have no idea what the width of our progressbar is going to be, which is why we need a little bit of math here. The width can change, the user can resize the control, the form can be maximized, anything can happen. We won’t know the width of the progress bar control until runtime.

int width = (int)(((percent / 100) * this.Width));

The user sets a percentage for the progress bar that is stored in the percent variable. Let’s say for instance that the user has selected 50% of the progress bar to be full, and sets the Value property to 50. Let’s also say the current width of the progress bar is 260 pixels.

This line of code will determine what width in pixels of the progress bar must be filled for the bar to display 50% completion:

Percent: 50.0
This.Width: 260
Percent / 100 = 0.5

260 * 0.5 = 130.0 (int)130.0 = 130. Therefore, due to the math above, we need to fill in 130 pixels of the bar exactly. As you can see, 130 pixels is exactly one half (50%) of 260 pixels.

The next line of code will do the actual drawing of the progress bar. With the Graphics object provided by our PaintEventArgs object, it is very easy to draw to the screen. Just simply call the FillRectangle function provided by the Graphics object, and you are in business.

e.Graphics.FillRectangle(b, 0, 0, width, this.Height);

The first parameter to the FillRectangle function is b, which is our solid color brush we created earlier in the function. That lets the function know what color to use for the rectangle. The second parameter is the x coordinate to place the top-left corner of the rectangle, and the third parameter is the y coordinate to place that corner. By providing 0s for these values, we place the top-left corner of the rectangle at the top-left corner of our progressbar control.

The last two parameters are the width of the rectangle and the height of the rectangle, respectively. We give the function the height of the control (this.Height) because we want it to fill in the entire height of the control, no matter what that height may be.

The last line in the function, b.Dispose() will cause the .Net framework to mark our brush object to be cleared from memory, so we don’t create a memory leak in the program.

Our Progress Bar Is Completed!

That’s right! That is all the code necessary to create a custom progress bar. We simply allow the programmer to select the color and the percentage completed, and the progress bar handles everything else in its own code.

Let's Give It A Whirl

Now let’s test our progress bar. In the solution explorer, double-click on “Form1.cs” to pull up the main form of the project. If you have not yet built the project, press F6 to build the project now.

In the toolbox window, you should see our ProgressControl as an available component that can be dragged to the form as a control. If you do not see the Toolbox window, go to View…Toolbox.


Drag a ProgressControl onto the form, and set the following properties on the control:

Dock: Top
Height: 25

Also drag a Timer control on the form. Set the following properties on Timer1:

Enabled: True
Interval: 300

Your form should now look like this image:

Double click on timer1 to pull up the code browser for its “Tick” property. Put in the following code:

private void timer1_Tick(object sender, EventArgs e)
{
if (progressControl1.Value <>
{
progressControl1.Value += 1;
}
else
{
timer1.Enabled = false;
MessageBox.Show("Done!");

Close();
}

}

As you can see, the timer will check to see if the progress of the bar is at 100%. If it is not, then it will increment the progress by 1. If the progress is completed, it will print up a message, disable the timer, and close the program.

Compile and run your program, and watch the progress bar in action!

I hope you have enjoyed reading this tutorial on .Net custom controls. More importantly, I hope I’ve helped you get started on a long and successful career as a programmer.

2 comments:

  1. colorBar Labels - print labels right from your own computer. We have web based and software. Print all your end tab labels yourself and save big

    ReplyDelete