(Print this page)

Creating your own Windows Custom Control
Published date: Saturday, March 1, 2003
On: Moer and Éric Moreau's web site

In this month column, I will show you how to create your own custom controls by extending existing control with new properties, methods or events. For those of you who have created some using VB6, you will soon discover that the process is now more straightforward and that it requires a lot less code because of the inheritance. 

Practically speaking, we will extend the textbox control to be a numeric only textbox with Min and Max values and accept validation with a regular expression.

Let's go!

So to start the creation of your own control, select Windows Control Library from the New Project dialog and name it MyOwnControls. This will create UserControl1.vb in MyOwnControls project and solution. Notice that a single project of that kind can host many controls of your own.

Change the (Name) property of your control from UserControl1 to MyOwnTextBox (from the Properties dialog) and rename UserControl1.vb to MyOwnTextBox.vb (by right-clicking UserControl1.vb from the Solution Explorer and selecting Rename). Now open the code editor of your control and change

Inherits System.Windows.Forms.UserControl

for

Inherits System.Windows.Forms.TextBox

If you stop here and compile what we have done so far, you will get just another working textbox! Our MyOwnTextBox already have everything it needs to be a textbox but that's not what we want!

For the purpose of the demo, add an ErrorProvider control (remember my February column?) to the MyOwnTextBox control (that will be used to display validation error).

Let's extend!

We will start by adding 3 properties to our textbox control: a min value, a max value and also a regular expression for validation.

Private mdblValueMax As Double
Private mdblValueMin As Double
Private mstrValidationExpression As String

Property ValidationExpression() As String
    Get
        Return mstrValidationExpression
    End Get
    Set(ByVal Value As String)
        Try
            If Value <> "" Then
                Dim dummy As Boolean
                dummy = Regex.IsMatch("abcde", Value)
            End If
            mstrValidationExpression = Value
        Catch ex As Exception
            MessageBox.Show(ex.Message, _
                            "Invalid value for this property", _
                            MessageBoxButtons.OK, _
                            MessageBoxIcon.Error)
        End Try
    End Set
End Property

Property ValueMax() As Double
    Get
        Return mdblValueMax
    End Get
    Set(ByVal Value As Double)
        mdblValueMax = Value
    End Set
End Property

Property ValueMin() As Double
    Get
        Return mdblValueMin
    End Get
    Set(ByVal Value As Double)
        mdblValueMin = Value
    End Set
End Property

Be warned that a public field cannot be used as a property (like you may have used in VB6). You have to write your own property procedure like in the previous example.

The constructor can now initialized some of the values. Find the New constructor and modify it to looks like this.

Public Sub New()
    MyBase.New()

    'This call is required by the Windows Form Designer.
    InitializeComponent()

    'Add any initialization after the InitializeComponent() call
    Me.ValueMin = 0
    Me.ValueMax = 100
    Me.ValidationExpression = "\d+"
End Sub

We will now ensure that user inputs are valid.

Private Sub MyOwnTextBox_KeyPress(ByVal sender As Object, _
              ByVal e As System.Windows.Forms.KeyPressEventArgs) _
               Handles MyBase.KeyPress
   'This code is pasted from a a Universal Thread question 
   'answered by Cathi Gero (January 28, 2003)
   Dim KeyAscii As Integer
   KeyAscii = Asc(e.KeyChar)

   Select Case KeyAscii

       Case 48 To 57, 8, 13
           ' don't do anything
       Case 45       
           If InStr(Me.Text, "-") <> 0 Then
               KeyAscii = 0
           End If

           If Me.SelectionStart <> 0 Then
               KeyAscii = 0
           End If
       Case 46                   
           If InStr(Me.Text, ".") <> 0 Then
               KeyAscii = 0
           End If

       Case Else
           KeyAscii = 0
   End Select

   If KeyAscii = 0 Then
       e.Handled = True
   Else
       e.Handled = False
   End If
End Sub

We now need a method that can be called when validation is needed. This method will use the previously declared properties.

Function Validate() As Boolean
    ErrorProvider1.SetError(Me, "")
    'Empty string not allowed
    If Me.Text = "" Then
        ErrorProvider1.SetError(Me, _
             "Value cannot be left empty!")
        Return False
    End If

    'Check min and max values
    If Me.ValueMin <> 0 Or Me.ValueMax <> 0 Then
        If Val(Me.Text) < Me.ValueMin Then
            ErrorProvider1.SetError(Me, _
                 "Value is less then the ValueMin!")
            Return False
        End If
        If Val(Me.Text) > Me.ValueMax Then
            ErrorProvider1.SetError(Me, _
                 "Value is higher then the ValueMax!")
            Return False
        End If
    End If

    If Me.ValidationExpression <> "" Then
        If Not Regex.IsMatch(Me.Text, _
                             Me.ValidationExpression) _
        Then
            ErrorProvider1.SetError(Me, _
                 "Pattern not respected!")
            Return False
        End If
    End If

    Return True
End Function

We now need to call this method when the content of the textbox changes.

Private Sub MyOwnTextBox_TextChanged(ByVal sender As Object, _
                                     ByVal e As System.EventArgs) _
                                     Handles MyBase.TextChanged
    Me.Validate()
End Sub

Let's compile!

This task is simple. From the Build menu, select the Build MyOwnControls item and your done. The result of the compilation will create a file with a DLL extension; so don't search for the OCX.

Let's test!

The easiest way to test your new creation is to add another project to your current solution. To do this, right-click your solution, select Add and then New Project … . From the Add New Project dialog, select a Windows Application. Just like when you were using multiple projects in a group in VB6, you need to set your testing project as the startup project. From the Solution Explorer, right click your test project and select Set as Startup Project.

If you now go into the Toolbox, you should now find MyOwnTextBox (should be completely at the bottom). Double-click on it and an instance of your textbox will be drawn on the form.

The control appeared in the toolbox because you are using a single solution. When you create a new application without having your control into the same solution, you need to add it to your toolbox. To do so, right click on the toolbox and select "Customize Toolbox". When a dialog appears, click on the .NET Framework Components tab. Then click on Browse... and pick the MyOwnControls.DLL.

Now select your control instance on your form and look at the properties, you will discover that all intrinsic properties of the textbox are already there. Have we done something for this? Yes. We have inherited!

Let's dance!

This is only the beginning of creating your own user controls. But as you can see the basis is easy enough for you to rapidly start building your own collection of specialized user controls.


(Print this page)