Adding a standard border to a control

The Control class doesn't have a border style property so creating controls with standard borders can present a problem. Many people assume the border is drawn in the OnPaint override but this creates a problem because it uses up some of the client rectangle which always has to be compensated for when doing the "real" drawing in a control. Really, the control border should be a non-client item and drawn for us by the system. The secret to enabling this feature is in the window creation parameters which are used every time a control is created or recreated.

The CreateParams property may be overridden to return a set of creation parameters that include the flags which add borders to the control. There also needs to be a mechanism for specifying which border is to be displayed so a property of type BorderStyle is ideal.

The basic control shown in the following C# and VB listings show how to do this.

VB

Imports System

Imports System.ComponentModel

Imports System.Windows.Forms

 

Namespace controlborders

 

    Public Class ControlEx

        Inherits Control

 

        Private _borderStyle As BorderStyle

 

 

        < _

        Category("Appearance"), _

        Description("The border style") _

        > _

        Public Property BorderStyle() As BorderStyle

            Get

                Return _borderStyle

            End Get

            Set(ByVal Value As BorderStyle)

                _borderStyle = Value

                Me.RecreateHandle()

                Invalidate()

            End Set

        End Property

 

 

        Protected Overrides ReadOnly Property CreateParams() As CreateParams

            Get

                Const WS_BORDER As Integer = &H800000

                Const WS_EX_STATICEDGE As Integer = &H20000

                Dim cp As CreateParams = MyBase.CreateParams

                Select Case _borderStyle

                    Case BorderStyle.FixedSingle

                        cp.Style = cp.Style Or WS_BORDER

                    Case BorderStyle.Fixed3D

                        cp.ExStyle = cp.ExStyle Or WS_EX_STATICEDGE

                End Select

                Return cp

            End Get

        End Property

 

 

        Public Sub New()

        End Sub 'New

    End Class 'ControlEx

End Namespace 'controlborders

 

C#

namespace controlborders

{

  using System;

  using System.Windows.Forms;

 

 

  public class ControlEx : Control

  {

   

    private BorderStyle _borderStyle;

 

    [

    Category("Appearance"),

    Description("The border style")

    ]

    public BorderStyle BorderStyle

    {

      get

      {

        return _borderStyle;

      }

      set

      {

        _borderStyle = value;

        this.RecreateHandle();

        Invalidate();

      }

    }

 

    protected override CreateParams CreateParams

    {

      get

      {

        const int WS_BORDER=0x00800000;

        const int WS_EX_STATICEDGE=0x00020000;

        CreateParams cp=base.CreateParams;

        switch (_borderStyle)

        {

          case BorderStyle.FixedSingle:

            cp.Style|=WS_BORDER;

            break;

          case BorderStyle.Fixed3D:

            cp.ExStyle |= WS_EX_STATICEDGE;

            break;

        }

        return cp;

      }

    }

 

    public ControlEx()

    {

    }

  }

}

 

Any class which derives from ControlEx will now have a BorderStyle property that can be used to select the FixedSingle or Fixed3D styles.

Return to the Tips and Tricks index

Copyright Robert W. Powell 2004. All rights reserved.