Edit

Share via


What is a custom control?

This article introduces you to custom controls and describes how they're different from user controls. Custom controls don't provide a visual design surface and rely on user-supplied code to draw themselves. This is different from user controls which provide a visual design surface to group multiple controls into a single reusable unit.

Custom controls are used when an existing control or user control doesn't come close to providing the UI or interactivity that you require. They require more effort on your part to fully implement. Keyboard and mouse handling is still provided by Windows Forms, but any behaviors are left up to you to implement. There isn't a design surface provided with a custom control, because all drawing is done through code in the OnPaint method. Components, such as a Timer, can still be added through the nonvisual design surface.

Base class

There are two base classes to choose from when creating a custom control:

Unless you require scrolling the contents of the custom control, use Control as your base class.

Inherited capabilities

Since the base class of a custom control is Control, you automatically inherit Windows Forms functionality shared by all controls. Here are a few of the capabilities you get with a custom control:

  • Keyboard and mouse input.
  • Layout behaviors, such as anchoring and docking.
  • Support for tabbing.
  • Minimum and maximum size restrictions.

Painting

Painting, which means to draw the control's visual, is accomplished by overriding the OnPaint method. For more information about how controls do painting, see Painting and drawing on controls.

When you create a custom control using the Visual Studio templates, the OnPaint method is automatically overridden for you. The template does this because you're required to write the code to draw your control. Here's an example of what the template generates:

public partial class CustomControl1 : Control
{
    public CustomControl1()
    {
        InitializeComponent();
    }

    protected override void OnPaint(PaintEventArgs pe)
    {
        base.OnPaint(pe);
    }
}
Public Class CustomControl1

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        'Add your custom paint code here
    End Sub

End Class

A custom control is painted with the OnPaint method. The single argument of this method is a PaintEventArgs object, which provides all of the information and functionality required to render your control. PaintEventArgs provides two properties that are used in rendering your control:

  • PaintEventArgs.ClipRectangle—Represents the part of the control that needs to be redrawn. This can be the entire control or part of the control.

  • Graphics—Represents the graphical surface of your control. It provides several graphics-oriented objects and methods that provide the functionality necessary to draw your control.

The OnPaint method is called whenever the control is drawn or refreshed on the screen, and the PaintEventArgs.ClipRectangle object represents the rectangle in which painting takes place. If the entire control needs to be refreshed, PaintEventArgs.ClipRectangle represents the size of the entire control. If only part of the control needs to be refreshed, it represents only the region that needs to be redrawn. An example of such a case would be when a control is partially obscured by another control in the user interface, and that other control is moved away, the newly exposed portion of the underneath control must be redrawn.

The code in the OnPaint method of a control runs when the control is first drawn and whenever it's invalidated. To ensure that your control is redrawn every time it's resized, add the following line to the constructor of your control:

SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.ResizeRedraw, True)

Example

The following code snippet is a custom control that renders multiple colored rectangles around the edge of the control.

protected override void OnPaint(PaintEventArgs pe)
{
    Rectangle rect = this.ClientRectangle;

    // Bring the width/height in by 1 pixel so the rectangle is drawn inside the control.
    // Otherwise, it kind of overlaps the outside edge.
    rect.Width -= 1;
    rect.Height -= 1;

    Pen[] colorPens = new Pen[] { Pens.Blue, Pens.BlueViolet,
                                  Pens.AliceBlue, Pens.CornflowerBlue,
                                  Pens.Cyan, Pens.DarkCyan };

    foreach (Pen pen in colorPens)
    {
        pe.Graphics.DrawRectangle(pen, rect);
        rect.Inflate(-1, -1);
    }

    // Raise the Paint event so users can custom paint if they want.
    base.OnPaint(pe);
}
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)

    Dim rect As Rectangle = Me.ClientRectangle

    'Bring the width/height in by 1 pixel so the rectangle is drawn inside the control.
    'Otherwise, it kind of overlaps the outside edge.
    rect.Width -= 1
    rect.Height -= 1

    Dim colorPens As Pen() = {Pens.Blue, Pens.BlueViolet,
                                Pens.AliceBlue, Pens.CornflowerBlue,
                                Pens.Cyan, Pens.DarkCyan}

    For Each curPen As Pen In colorPens

        e.Graphics.DrawRectangle(curPen, rect)
        rect.Inflate(-1, -1)

    Next

    'Raise the Paint event so users can custom paint if they want.
    MyBase.OnPaint(e)

End Sub

The previous code creates a control that looks like the following image:

A custom control as rendered in Visual Studio. The control is an empty box with different colors bordering it. Each color is inset by a single pixel.

Background

Notice that the background of the control is painted with the SystemColors.Control color, even though the OnPaint code doesn't clear or fill the control with a color. The background is actually painted by the OnPaintBackground(PaintEventArgs) method before OnPaint is called. Override OnPaintBackground to handle drawing the background of your control. The default implementation of this method is to draw the color and image set by the BackColor and BackgroundImage properties, respectively.