Customize and Extend Windows Forms Controls

ith Visual Studio 2005, developing Windows Forms applications has never been easier. In the user interface area, Microsoft has provided much of the needed functionality in the form of Windows Forms controls, such as the familiar Button and TextBox controls. Using the controls greatly simplifies the developmental process?simply drag and drop the controls, configure their properties, and service all the necessary events.

However, despite the comprehensive set of functionality, there are times where you need to enhance the controls with new features. A good example is the TextBox control. As you are probably aware, the TextBox control allows users to input data into your application. But it does not provide any sort of validation (such as verifying that the input data is an email address) and input filtering (such as restricting input to numbers). To do so, you need to write your own custom validation and filtering logic for each individual TextBox control. Imagine how much work it would be if you needed to validate a dozen instances of this control; you’d have to write a lot of repetitive code.

A better option is to extend the built-in controls so that they can be used as new controls (enhanced with new features). In this article, I will use a specific example?the TextBox control?to show you how you can extend Windows Forms controls. I will extend the TextBox control so that it will perform the following:

  • Restrict data input through filtering. You can specify the type of data the user can enter, such as numeric (integer or decimal numbers), alphabetic characters only, or alphanumeric.
  • Enforce casing. You can specify if the entered data will appear in lower or upper case.
  • Precision formatting. You can specify if the numbers entered will appear in one, two, or three decimal places.
  • Custom validation. You can use regular expression to perform custom validation, such as verifying social security numbers, zip codes, or email addresses.

The second section of this article will show how you can combine Windows Forms controls into one single control (known as a user control).

Extending Windows Forms Controls
Using Visual Studio 2005, create a new Windows application and name it WindowsControls. This Windows application project will act as the host for the controls that you will be extending shortly.

Now, add a new Class Library project (File | Add | New Project?) to the current solution and name the project EnhancedTextBox.

As you are going to extend a Windows Forms control in this project (specifically the TextBox control), add a reference to System.Windows.Forms (right-click on the EnhancedTextBox project name in Solution Explorer and select Add Reference?).

Import the following namespaces:

Imports System.Windows.FormsImports System.ComponentModel

Next, define the following enumerations (in bold) for the different types of casings, filters, and the different levels of precisions:

Imports System.Windows.FormsImports System.ComponentModelPublic Enum Cases    Mixed    UpperOnly    LowerOnlyEnd EnumPublic Enum FilterTypes    None    IntegerNumeric    DecimalNumeric    AlphabetsOnly    AlphanumericEnd EnumPublic Enum Precisions    None    OneDecimal    TwoDecimal    ThreeDecimalEnd Enum

And since you are extending the TextBox control, you need to inherit the EnhancedTextBox class from System.Windows.Forms.TextBox:

Public Class EnhancedTextBox    Inherits System.Windows.Forms.TextBox

Declaring the Member Variables
You can now declare the member variables to store the filter type, casing, precision, as well as the regular expression as set by the user. Also, define an event so that when the validation fails, the user of the control can react appropriately:

 _Public Class EnhancedTextBox    Inherits System.Windows.Forms.TextBox    '---member variables for filtering---    Private _filterType As FilterTypes = FilterTypes.None    Private _casing As Cases = Cases.Mixed    Private _precision As Precisions = Precisions.None    '---member variables for regular expression validation---    Private _regex As String    Private _regexErrMsg As String    '---event handler for error---     _    Public Event Err(ByVal str As String)

Notice that I have marked the class with a DefaultEventAttribute that specifies the Err as the default event handler. I have also marked the Err event with the CategoryAttribute to associate it with the Custom Properties category in the Properties window (you will see this in action later). The DescriptionAttribute specifies the description for this event.

Declaring the Properties
You will next declare the various properties that allow the user to control the types of filter, precisions, and casing they want, as well as enter the regular expression to use for custom validation.

The Precision property specifies the number of decimal places with which to format the text input:

    '---property for setting precision---     _    Public Property Precision() As Precisions        Get            Return _precision        End Get        Set(ByVal value As Precisions)            _precision = value        End Set    End Property

The EnforceCasing property indicates if the character entered should automatically be converted to upper or lower casing:

    '---property for enforcing casing---     _    Public Property EnforceCasing() As Cases        Get            Return _casing        End Get        Set(ByVal value As Cases)            _casing = value        End Set    End Property

The FilterType property specifies the types of characters allowed for entry:

    '---property for setting filter types---     _    Public Property FilterType() As FilterTypes        Get            Return _filterType        End Get        Set(ByVal value As FilterTypes)            _filterType = value        End Set    End Property

The RegularExpression property allows the user to set the regular expression to be used for custom validation:

    '---property for setting the regular expression---    _   Public Property RegularExpression() As String       Get          Return _regex       End Get       Set(ByVal value As String)           _regex = value       End Set   End Property

And finally, the RegularExpressionErrorMessage property allows the user to specify the error message to display in a balloon should the regular expression validation fail:

    '---property for error message to display if regular expresson     ' validation fails---     _        Public Property RegularExpressionErrorMessage() As String        Get            Return _regexErrMsg        End Get        Set(ByVal value As String)            _regexErrMsg = value        End Set    End Property

Servicing the Events
The final step is to service the various events associated with the TextBox control. To ensure that users can enter only the characters specified by the filter, you can service the KeyPress event of the TextBox control. The KeyPress event is fired whenever the user presses a key when the focus is on the TextBox control. This is the event to service so that only the allowed characters/digits are allowed to be shown in the TextBox control. The code for the KeyPress event is shown in Listing 1.

Here, you check for various types of characters that the user may enter. If an invalid character is detected, the e.Handled property is set to True and the character will not be added to the TextBox. The IsControl() method checks to see if a character entered is a control character (such as Tab, Carriage Return, BackSpace, etc). It is important that you check for control characters. Why? One good example is the BackSpace character. If the BackSpace character is ignored in the KeyPress event, then the user might not be able to erase a character entered in a TextBox control by using the BackSpace key. That would be bad user interface design.

While servicing the KeyPress event can prohibit users from entering illegal characters, you still need to do some more work in another event?the LostFocus event. The LostFocus event is fired when the focus is transferred from the TextBox control to somewhere else, such as pressing the Tab key to navigate to the next control.

A very important task you need to perform in this event is to validate the content of the TextBox control. This is because illegal characters can still seep into the control by methods other than direct entry through the keyboard; a user could assign the value of the TextBox control programmatically or paste (Ctrl-V) illegal characters into a TextBox control. For example, if you set a TextBox control with the IntegerNumeric filter, you are still able to programmatically assign a decimal numeric value to it through code. In this case, the KeyPress event cannot be used to restrict the assignment. Hence, in the LostFocus event you need to perform the various types of validation to ensure that the value in the TextBox control conforms to the specified filter. The code for the LostFocus event is shown in Listing 2.

The ShowErrorBalloon() method displays a message in a balloon using the ToolTip control:

    Public Sub ShowErrorBalloon(ByVal str As String)        Dim toolTip1 As New ToolTip        With toolTip1            .IsBalloon = True            .Show(str, Me, 10, -40, 2000)        End With    End Sub

Testing the Extended TextBox Control
You are now ready to test the extended TextBox control. Right-click on the EnhancedTextBox project in Solution Explorer and select Build to compile the project into a DLL.

Back in the WindowsControls project, right-click on the Common Controls tab in Toolbox and select Choose Items? (see Figure 1).


Figure 1. Add a new control to the ToolBox.
?
Figure 2. Select the EnhancedTextBox.dll.

In the Choose ToolBox Items window, click the Browse? button and navigate to the binDebug folder of the project and select EnhancedTextBox.dll (see Figure 2). Click Open.

The EnhancedTextBox control will now appear in the ToolBox. Drag and drop a copy of it onto the default Form1 of the WindowsControls project (see Figure 3).


Figure 3. Drag and drop the EnhancedTextBox control onto Form1.
?
Figure 4. Locate the properties and event of the EnhancedTextBox control.

Right-click on the newly added EnhancedTextBox control and select Properties. Recall the properties and event that you defined earlier in the EnhancedTextBox project. They can now be found in the Properties window. If you switched to Categorized view, you will find them located under the custom-defined CustomProperties category (see Figure 4). You can set the various properties using the Properties window.

Alternatively, you can also set the properties programmatically through code, like this:

        '---here is one example---        With EnhancedTextBox1            .FilterType = EnhancedTextBox.FilterTypes.DecimalNumeric            .Precision = EnhancedTextBox.Precisions.TwoDecimal        End With        '---another example---        With EnhancedTextBox1            .RegularExpression = _               "^[w-.]{1,}@([da-zA-Z-]{1,}.){1,}[da-zA-Z-]{2,3}$"            .RegularExpressionErrorMessage = _               "Email address is not correct"        End With

To thoroughly test the new extended control easily, I have added some controls to the form (see Figure 5). The form also shows the logical relationships between all the various filters. For example, if you select the DecimalNumeric filter, then only the Precision formatting applies. Alternatively, if you select either the AlphabetsOnly or Alphanumeric filter, then only the EnforceCasing formatting applies. If a regular expression is entered, then the text entered will be validated after it loses its focus.

Author’s Note: You can download the sample application accompanying this article.


Figure 5. The screen shot shows testing of the EnhancedTextBox control.
?
Figure 6. The balloon is used to show the user that the validation failed.

If the text entered does not pass the validation, a balloon will be shown (see Figure 6).

Developing User Controls
In the previous section, you saw how to extend the built-in TextBox control with various filters and formatting. You can now easily use the newly enhanced TextBox control to perform all sorts of input filtering and not worry about the innards of how it works.

Besides extending individual Windows Forms controls, you can also group them into one single control. This is accomplished by the project type known as a Windows Control Library. Using the enhanced TextBox control created in the previous section, you might want to combine a few of these controls together to form a new control, for example, a control that contains two TextBox controls to allow the user to enter his name and email address. Let?s see how this can be done.

Using the same solution, add a new Windows Control Library project to the existing solution and name the project WindowsControlLibrary1. You can see the default design of the control in Figure 7.


Figure 7. The design surface of the user control is shown.
?
Figure 8. Populate the user control with a label and enhanced TextBox controls.

Populate the design surface with the following controls (see also Figure 8):

  • Label
  • EnhancedTextBox

Set the properties for the various controls as shown in Table 1.

Table 1. Properties values for the various controls

Control Property Value
UserControl1 BorderStyle FixedSingle.
txtE_Name FilterType AlphabetsOnly
txtE_Email RegularExpression “^[w-.]{1,}@([da-zA-Z-]{1,}.){1,}[da-zA-Z-]{2,3}$”
txtE_Email RegularExpressionErrorMessage “Email is incorrect.”

Switch to the code-behind of the user control by double-clicking on its design surface. Here, you will add two member variables and two properties to allow the user to set the user name as well as email address:

Public Class UserControl1    Private _Name As String    Private _Email As String    Public Property UserName() As String        Get            Return txtE_Name.Text        End Get        Set(ByVal value As String)            txtE_Name.Text = value        End Set    End Property    Public Property Email() As String        Get            Return txtE_Email.Text        End Get        Set(ByVal value As String)            txtE_Email.Text = value        End Set    End Property

In the design surface of the user control, when you double-click on the txtE_Email control, the Err event handler will be automatically created for you (recall that the default event for the EnhancedTextBox control is Err):

    Private Sub txtE_Email_Err(ByVal str As System.String) _       Handles txtE_Email.Err        With txtE_Email            .BackColor = Color.LightYellow        End With    End Sub

This event would be fired whenever there is an error with the validation. For this instance, you would set the background color of the control to light yellow should the validation fail.

Testing the User Control
You are now ready to test the new user control. Right-click on the UserControl project in Solution Explorer and select Build to compile the project into a DLL.

Back in the WindowsControls project, right-click on the Common Controls tab in Toolbox and select Choose Items?. In the Choose ToolBox Items window, click the Browse? button, navigate to the binDebug folder of the project, and select WindowsControlLibrary1.dll. Click Open. The user control should now be visible in the ToolBox. Drag and drop it onto the bottom of Form1 (see Figure 9).


Figure 9. The new user control is in action.
?
Figure 10. The error message to inform the user that the input validation has failed is shown in a yellow balloon.

Try entering your name in the first control and press Tab to go to the next. If you enter an invalid email address and then press Tab to cause it to lose its focus, a balloon will appear and the background color of the control is changed to light yellow (see Figure 10).

In this article, you have seen how to extend Windows Forms controls and package them as new controls. Extending Windows Form controls can save a lot of time when you are using the same control over and over again. This is especially true in big development projects where you have a lot of repetitive functions.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: