
Contents
In this tutorial we will walk through the process of creating a
custom Windows Forms control from the start of the project all the way to
inclusion in the Visual Studio ToolBox. The control will be a simple DividerPanel - an
inherited Panel control that features selectable border appearance and border
sides. After completing this tutorial, readers should have a basic
foundation on class inheritance, creating custom properties, overriding base
methods, using property comments, creating a ToolBox icon, creating a
simple designer class and integrating a custom control into the Visual Studio
ToolBox. Along the way we will discuss some best practices and detail some
shortcuts in Visual Studio that help to simplify control development.

When creating a new project in Visual Studio for control development, it's usually a
good idea to start with a new Blank Solution rather than jumping
straight into a new Control Library project with the project wizard. In doing
so, you can create multiple projects within the one solution -
this allows your test application and control library to remain as separate
projects, and also adds the ability to easily share linked classes and
include global solution items.
To create a new Blank Solution, select File >
New > Blank Solution. In the New Solution
dialog, enter the solution name as Windows Forms Divider Panel
and click OK.

Once your new solution has been created, right-click on the
solution title and select Add > New
Project. When the Add New Project dialog opens, select the
Windows Control Library option, and enter DividerPanel
as the project name.
The wizard will create the control library with two files by
default: UserControl1.cs and AssemblyInfo.cs. For this tutorial we will delete
UserControl1.cs and create our control in a new, empty class.
Highlight UserControl1.cs then right-click and
select Delete to remove it from the project.

Next, right-click on the DividerPanel project in Solution
Explorer, then select Add > Add Class from
the context menu. In the Add Class dialog, enter
DividerPanel.cs as the class name and click
OK.
Inheritance is one of the major factors that makes object oriented
programming so powerful. When we inherit from an existing class we automatically
pick up all of the base classes' functionality and gain the ability to extend
upon it to create a more specialized class. All Windows Forms controls at some
point must inherit from System.Windows.Forms.Control, as it encapsulates all of
the basic properties and methods the framework needs to host a class as a
control on a Form.
Fortunately inheriting from an existing control is a snap - once you have
decided the control that has the base functionality you wish to extend upon, it
takes just one addition to your class declaration line to make your class
inherit from it:
public class DividerPanel : System.Windows.Forms.Panel
{
}
For our DividerPanel control, we have specified that we are inheriting our
base functionality from the standard System.Windows.Forms.Panel control. In
doing this, our new control now has all of the Properties and Methods of the
Panel control - we can now add our own custom properties to
it, and override some of the Panel controls methods in order to
implement our customizations.
In order to implement our DividerPanel, we are going to add two new
properties: BorderSide and Border3DStyle. For the
BorderSide property we will
be using a reference to a value from the System.Windows.Forms.Border3DSide
enumeration, and for the Border3DStyle property we will be using a
reference to a value from the System.Windows.Forms.Border3DStyle enumeration.
While there a few different ways we can expose these properties, there is
only one good way - create a private variable for use by methods within our
control class, and a complementary public accessor for exposing the
property to other classes that will use the control, like so:
private System.Windows.Forms.Border3DSide borderSide;
private System.Windows.Forms.Border3DStyle border3DStyle;
public System.Windows.Forms.Border3DSide BorderSide
{
get { return this.borderSide; }
set
{
if( this.borderSide != value )
{
this.borderSide = value;
this.Invalidate();
}
}
}
public System.Windows.Forms.Border3DStyle Border3DStyle
{
get { return this.border3DStyle; }
set
{
if( this.border3DStyle != value )
{
this.border3DStyle = value;
this.Invalidate();
}
}
}
In the above code we first define two private properties: borderSide and
border3DStyle - these are the variables we will use within our class. As these
are both defined with the private attribute they cannot be accessed by any code
outside of our control class. You will also note that I have specified the full
path to the property objects -
private System.Windows.Forms.Border3DSide borderSide;
As I have included a using System.Windows.Forms directive for my class I
could have just declared the property as:
private Border3DSide borderSide;
But it is always good practice to include the full path to alleviate possible
naming obscurities.
Next we have two public properties, both using get and
set accessors. In both cases the get accessor simply returns the
value of our private property, while the set accessor first checks if the value
being set differs from current, and only if so it updates our private property
and calls the Invalidate() method to force our control to
repaint.
We could have simply created two public only properties as in the sample
below, but then we could not do any processing such as the
Invalidate() call on set, and there would be no way for our
class to know when a value had been changed.
public System.Windows.Forms.Border3DSide BorderSide;
public System.Windows.Forms.Border3DStyle Border3DStyle;
Even if you don't intend on doing any processing in you public accessors, you
should still always stick to good quality coding conventions such as
this. The next point is my choice of naming conventions - many people
still use naming conventions from other languages such as
m_BorderSide instead of my choice of borderSide. My
personal choice is based on 3 different sources: first is the names that
Visual Studio will automatically assign to controls that are dragged and dropped from
the ToolBox, and second is that fact that the framework itself uses
this naming convention for most of its
private properties (a quick look at any
of the framework classes with a decompiler or reflector will confirm this fact).
If Microsoft decided it was the best practice naming convention for the .Net
framework itself, it's natural to assume it's the best practice when coding for
the .Net framework.
The third reason for not using
prefixes such as m_ to denote member variables is that you cannot take
full advantge of Visual Studio's Intellisense
features if you do so. Which brings me to another point of note in the accessor
code, my usage of the
this prefix - technically there is no need and no advantage in
using the this directive in the above accessor code. However, by
using the this directive you can take advantage of Intellisense's auto
word completion system to fill in the rest of your variable name, saving coding
time and saving possible problems with typos.
Any variables you define should always be explicitly assigned a value before
they are used. Always set initial values in the class's constructor, or in a
method called fom your constructor. Variables without initial value assignments
can sometimes create problems that can take hours to find at a later time. For
our DividerPanel class, the Constructor looks like this:
public DividerPanel()
{
this.borderSide = System.Windows.Forms.Border3DSide.All;
this.border3DStyle = System.Windows.Forms.Border3DStyle.Etched;
}
The constructor is the first method called in any class, and is called upon
instantiation. You would normally carry out any initialization work necessary
here, to ensure that everything is ready to go before any other methods can be
called by code using your class. Constructors are always named the same as their
parent class, and every class that is to be used as a control must have a
parameter-less public constructor if it is to be used with the Visual Studio designer,
or be visible to COM clients.
When you override a method from a base class, the CLR will run your code
instead of the code normally contained in the base class's corresponding method.
This allows you to easily change the behaviour and extend upon the functionality
of most of the base controls in the framework. In order to add a border to our
DividerPanel, we are going to override the OnPaint method in the
base Panel control. Once we have overidden a base class's method, we can
still call the base functionality by using the base keyword.

Naturally every method has it's own unique parameters and in order to perform
an override we need to know exactly what those parameters are.
Fortunately Visual Studio
makes it a snap for us to add overrides when
creating custom controls. On the right side of the Visual Studio window you have the
Solution Explorer displayed by default, at the bottom of the
Solution Explorer panel, click the tab labelled Class View .
Next expand out the DividerPanel class and you will see something the same as
pictured above.
The Class View is also handy for understanding the path of inheritance your
control uses. In our case we can see that our inheritance path is: DividerPanel
< Panel < ScrollableControl < Control <
Component < MarshallByRefObject < Object.

For our DividerPanel control, we need to override the
OnPaint method, which as you will see is inherited all the way down
the tree from the Control class. Locate the OnPaint method,
right-click it and select Add >
Override.
Visual Studio will then insert an overridden version of the OnPaint
method into our class, and we can then add the code that will give our
control it's extended functionality
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
base.OnPaint(e);
System.Windows.Forms.ControlPaint.DrawBorder3D (
e.Graphics,
this.ClientRectangle,
this.border3DStyle,
this.borderSide );
}
The first line we'll add to the overriden method is
base.OnPaint(e); - this line executes the overridden code from the
Panel control, passing the PaintEventArgs value. If we excluded this
base.OnPaint(e); method call, we would have to take care of
painting everything that our DividerPanel needs ourselves, which of course means
we would have to write code that handles all of the painting required for a
Panel control.
After the base control has been painted (and only after) we use the
System.Windows.Forms.ControlPaint.DrawBorder3D method
to paint our custom border(s) over the top of the Panel
control, using the values from the custom properties we added earlier. As a side
note, the System.Windows.Forms.ControlPaint class is worth your
time to investigate as it contains a bevy of static methods that simplify the
painting of many Windows type controls such as Buttons, CheckBoxes,
RadioButtons, Grids etc.
At this stage we now have a fully functional DividerPanel control, that could
be compiled and manually referenced in an application, but don't stop now
because we are far from finished!
In order to make our control look and feel like one from the framework
ToolBox, we need to add descriptions to our new public accessors, and create a
new properties group. Without this, our new properties will be listed as Misc,
and it will not be clear exactly what our new properties are intended to do to
other developers. Once again, adding property descriptions is a snap, and while
we're at it well include support for creating Xml documentation files which can
later be created with utilities such as NDoc.
To achieve these, we'll modify our public accessors using the code
sample below. The <summary> lines are used to generate Xml documentation
files by Visual Studio - to add a summary to any property or class, simply position the
caret to a line directly above your property/class and enter three forward
slashes (///). Visual Studio will automatically build the required summary structure
and all you need to do is fill in the blanks.
The next addition we make here is the designer attributes line, starting with
the Bindable attribute. We'll step through the attributes added here one by
one:
Bindable(true) - When set to true, any changes to this property will raise a
property changed notification, which makes your designer class (discussed later)
aware of changes made at design time.
Category("Border Options") - The Category attribute specifies where this
property should be grouped in the Properties panel of the forms designer. If
this attribute is not set, your new property will be listed under "Misc".
DefaultValue(System.Windows.Forms.Border3dSide.All) - this attribute tells
the Visual Studio designer what the default value of the property is, and is used to
highlight changes from the default value with bold text. In our screenshot
you can see that the value "Etched" is not in bold because we are using the
default value, but the value "Top" is in bold because we have changed it from
the default value of "All". Note that this attribute has nothing to do with the
default value assigned to the property - you must still set a default value for
all properties in your controls' constructor.
Description("Specifies the sides of the panel to apply a three-dimensional
border to.") - the Description value is displayed at the bottom of the
properties panel whenever a property is selected, and should clearly convey to
developers what the property does.
[Bindable(true), Category("Border Options"),
DefaultValue(System.Windows.Forms.Border3DSide.All),
Description("Specifies the sides of the panel to apply a
three-dimensional border to.")]
public System.Windows.Forms.Border3DSide BorderSide
{
get { return this.borderSide; }
set
{
if( this.borderSide != value )
{
this.borderSide = value;
this.Invalidate();
}
}
}
[Bindable(true), Category("Border Options"),
DefaultValue(System.Windows.Forms.Border3DStyle.Etched),
Description("Specifies the style of the three-dimensional border.")]
public System.Windows.Forms.Border3DStyle Border3DStyle
{
get { return this.border3DStyle; }
set
{
if( this.border3DStyle != value )
{
this.border3DStyle = value;
this.Invalidate();
}
}
}
Adding Toolbox support to our new control is just a simple, and involves
creating a bitmap to be used as a Toolbox icon for our control, and setting a
couple of attributes so that Visual Studio knows how to display our control in the
Toolbox.

To create an icon for our control, right-click on our DividerPanel project
entry in Solution Explorer, then click Add > New
Item. In the dialog that opens, select Bitmap File and
set the name to DividerPanel.bmp.
Now highlight DividerPanel.bmp in Solution Explorer and set the Build
Action to Embedded Resource.
Next Open the DividerPanel.bmp for editing, and set both the
Height and Width to 16, and set the
Colors property to 16.
Now paint your icon bitmap and save it:

The final step is to add two new attributes to our DividerPanel class, so
that the compiler knows to associate the bitmap and to allow the control to be
included in the Visual Studio Toolbox:
[ToolboxItem(true)]
[ToolboxBitmap(typeof(DividerPanel))]
public class DividerPanel : System.Windows.Forms.Panel
{
}
The first attribute we are adding allows our class to be used as a
Toolbox item - if you omit this attribute Visual Studio will imply it is already
set to true, but as always it is good coding practice to explicitly set this
attribute so that
your original intentions are always clear when revisting your code. The second line
tells the compiler to associate the DividerPanel.bmp file with our control. The
name specified in this attribute is simply the resource name of the bitmap,
excluding the .bmp extension. As a final note, Toolbox icons must always be
bitmap files, with a maximum color depth of 16 colors, and dimensions of
16x16.
We could now compile our control, add it to the Toolbox and start dragging
onto Forms at will, but there's one potential problem we need to address
first:
The Panel control we derived from has a BorderStyle property
which can be set to None, FixedSingle or Fixed3D - as we are going to be
painting our custom border over the top of the standard Panel control, we should
remove the BorderStyle property so that there's no confusion about
which property developers should use, and also to avoid ugly visual artifacts
from someone setting styles for both sets of properties.
There are a few ways to achieve the result we want, but the cleanest way is
to create a simple designer class that filters the property list, removing
BorderStyle from the properties window altogether. Doing it this
way leaves the BorderStyle property intact so that developers can
still set it programmatically in their code should they wish to do so.
To start our designer class, right-click on the DividerPanel project in
Solution Explorer, then select Add > Add
Class from the context menu. In the Add Class dialog, enter
DividerPanelDesigner.cs as the class name and click
OK.
To implement our designer class, our project needs to reference
System.Design.dll from the framework. To add the reference, right-click on
References in Solution Explorer, then click Add
Reference. In the Add Reference dialog, select System.Design.dll as
pictured above, and click OK.
Open DividerPanelDesigner.cs, and change the Class line so that we are
inheriting from the
System.Windows.Forms.Design.ScrollableControlDesigner class:
public class DividerPanelDesigner :
System.Windows.Forms.Design.ScrollableControlDesigner
{
}

Now change to Class View and expand our DividerPanelDesigner class until you
get down to the ControlDesigner class, the inheritance path being:
DividerPanelDesigner < ScrollableControlDesigner < ParentControlDesigner
< ControlDesigner. Now locate the PreFilterProperties method, right-click it
and select Add > Override.
As before, Visual Studio will automatically add the overridden method into our
designer class code. All we have to do now is add the code to filter out our
unwanted BorderStyle property:
protected override void PreFilterProperties(
System.Collections.IDictionary properties)
{
properties.Remove("BorderStyle");
}
And finally add a designer attribute to our DividerPanel class to link our
designer class like so:
[ToolboxItem(true)]
[ToolboxBitmap(typeof(DividerPanel))]
[DesignerAttribute(typeof(DividerPanelDesigner))]
public class DividerPanel : System.Windows.Forms.Panel
{
}
For this tutorial that's all our designer class needs to do, so we'll leave
it at that for now. Creating designer classes is a good subject for a book, not
a simple tutorial such as this, but at least you now have an
introduction on how to create and use them.
The final steps we should do before releasing our new control on the
unsuspecting public are related to the compilation process. The additions
discussed here are all non-essential but do represent best practice coding and a
very small amount of work, so there's no reason to omit them.
First we'll open up the AssemblyInfo.cs file and provide some values to
the default assembly attributes as follows:
[assembly: AssemblyTitle("Divider Panel")]
[assembly: AssemblyDescription(
"A Panel control with selectable border appearance")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("CodeShack")]
[assembly: AssemblyProduct("Divider Panel Tutorial")]
[assembly: AssemblyCopyright("Copyright (c) 2003-2004 CodeShack")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
Next we'll add a couple more assembly attributes that are not included by
default (I'll let my code comments speak for themselves):
[assembly: System.CLSCompliant(true)]
[assembly: System.Runtime.InteropServices.ComVisible(true)]
And now the final step before we can use our new control, signing your
assembly. Signing your assembly is always good practice as it prevents
modified or corrupted libraries from being loaded, protecting the application
using it against things such as download errors or tampering.

First we must use the Strong Name utility provided with Visual Studio to create a
new public/private key pair for our assembly. To do this open up the Visual
Studio Command Prompt by clicking Start > All Programs > Visual Studio.Net
> Visual Studio .Net Tools > Visual Studio Command Prompt.
At the command prompt enter:
sn -k [outputfile].snk
If you didn't specify the output file to be in your project directory, copy
it there now and then modify the AssemblyInfo.cs file as follows, so that Visual Studio
knows the relative path to your key file:
[assembly: AssemblyKeyFile("..\\..\\..\\DividerPanel.snk")]
Now all that's left is to build our control, and add it to the Toolbox so we
can use it in our applications. Once you are satisfied that your control is
bug-free and feature complete, change the Build Configuration in Visual Studio to
Release and hit F5 to to compile it.

Next create a new Windows Application project and open a form in design view
so that the Windows Forms Toolbox is visible. Right-click on the Toolbox and
select Customize Toolbox, when the Customize Toolbox dialog
opens, click the .Net Framework Components tab, click
Browse, locate the DividerPanel.dll file in the bin\Release
directory and click OK.
You will now see the DividerPanel control in the Toolbox items list, and you
are ready to start dragging it into your applications.

In this tutorial we have touched on the following topics:
- Creating a blank solution as a better starting point for a control project
- Inheriting functionality from existing controls
- Adding new Properties and Accessors to a control class
- Property naming conventions
- Overriding inherited methods
- Adding property descriptions and documentation support
- Adding Visual Studio Toolbox support
- Simple designer class creation and usage
- Specifying assembly attributes and signing a library using the strong name
tool
- Adding a custom control to the Visual Studio Toolbox
Release History
- Version 1.0: 29 August 2003 - Initial posting
- Version 1.01: 12 September 2004 - Edited some terminology, added additional tips.