As you can see, it’s quite trivial to create a new custom control by inheriting any of the built-in Windows controls. Of course, what good is a control that’s identical to an existing one? Let’s add some extra functionality to our custom TextBox control. Switch to the control project and view the FocusedTextBox object’s code. In the code editor’s pane, expand the Objects list and select the item FocusedTextBox Events. This list contains the events of the TextBox control because it is the base control for our custom control.
Expand the Events drop-down list and select the Enter event. The following event handler declaration will appear:
Private Sub FocusedTextBox Enter(...) Handles Me.Enter
End Sub
Code language: CSS (css)
This event takes place every time our custom control gets the focus. To change the color of the current control, insert the following statement in the event handler:
Me.BackColor = Color.Cyan
(Or use any other color you like; just make sure it mixes well with the form’s default background color. You can also use the members of the SystemColors enumeration, to help ensure that it mixes well with the background color.) We must also program the Leave event, so that the control’s background color is reset to white when it loses the focus. Enter the following statement in the Leave event’s handler:
Private Sub FocusedTextBox_Leave(...) Handles Me.Leave
Me.BackColor = Color.White
End Sub
Code language: PHP (php)
Having a hard time picking the color that signifies that the control has the focus? Why not expose this value as a property, so that you (or other developers using your control) can set it individually in each project? Let’s add the EnterFocusColor property, which is the control’s background color when it has the focus.
Because our control is meant for data-entry operations, we can add another neat feature. Some fields on a form are usually mandatory, and some are optional. Let’s add some visual indication for the mandatory fields. First, we need to specify whether a field is mandatory with the Mandatory property. If a field is mandatory, its background color will be set to the value of the MandatoryColor property, but only if the control is empty.
Here’s a quick overview of the control’s custom properties:
EnterFocusColor – When the control receives the focus, its background color is set to this value. If you don’t want the currently active control to change color, set its EnterFocusColor to white.
Mandatory – This property indicates whether the control corresponds to a required field if Mandatory is True or to an optional field if Mandatory is False.
MandatoryColor – This is the background color of the control if its Mandatory property is set to True. The MandatoryColor overwrites the control’s default background color. In other words, if the user skips a mandatory field, the corresponding control is painted with the MandatoryColor, and it’s not reset to the control’s background color. Required fields behave like optional fields after they have been assigned a value.
If you have read the previous chapter, you should be able to implement these properties easily. Listing 8.1 is the code that implements the four custom properties. The values of the properties are stored in the private variables declared at the beginning of the listing. Then the control’s properties are implemented as Property procedures.
Listing 8.1: Property Procedures of the FocusedTextBox
Dim _mandatory As Boolean
Dim _enterFocusColor, _leaveFocusColor As Color
Dim _mandatoryColor As Color
Property Mandatory() As Boolean
Get
Mandatory = _mandatory
End Get
Set(ByVal value As Boolean)
_mandatory = Value
End Set
End Property
Property EnterFocusColor() As System.Drawing.Color
Get
Return _enterFocusColor
End Get
Set(ByVal value As System.Drawing.Color)
_enterFocusColor = value
End Set
End Property
Property MandatoryColor() As System.Drawing.Color
Get
Return _mandatoryColor
End Get
Set(ByVal value As System.Drawing.Color)
_mandatoryColor = value
End Set
End Property
Code language: PHP (php)
The last step is to use these properties in the control’s Enter and Leave events. When the control receives the focus, it changes its background color to EnterFocusColor to indicate that it’s the active control on the form (the control with the focus). When it loses the focus, its background is restored to the usual background color, unless it’s a required field and the user has left it blank. In this case, its background color is set to MandatoryColor. Listing 8.2 shows the code in the two focus-related events of the UserControl object.
Listing 8.2: Enter and Leave Events
Private _backColor As Color
Private Sub FocusedTextBox Enter(...) Handles MyBase.Enter
_backColor = Me.BackColor
Me.BackColor = _enterFocusColor
End Sub
Private Sub FocusedTextBox Leave(...) Handles MyBase.Leave
If Trim(Me.Text).Length = 0 And _mandatory Then
Me.BackColor = _mandatoryColor
Else
Me.BackColor = _backColor
End If
End Sub
Code language: PHP (php)
Testing the FocusedTextBox Control
Build the control again with the Build ➤ Build FocusedTextBox command and switch to the test form. Place several instances of the custom control on the form, align them, and then select each one and set its properties in the Properties window. The new properties are appended at the bottom of the Properties window, on the Misc tab (for miscellaneous properties). You will see shortly how to add each property under a specific category, as shown in Figure 8.3. Set the custom properties of a few controls on the form and then press F5 to run the application. See how the FocusedTextBox controls behave as you move the focus from one to the other and how they handle the mandatory fields.
Figure 8.3 – Custom properties of the FocusedTextBox control in the Properties window
Pretty impressive, isn’t it? I’m certain that many readers will incorporate this custom control in their projects — perhaps you may already be considering new features. Even if you have no use for an enhanced TextBox control, you’ll agree that building it was quite simple. Next time you need to enhance one of the Windows controls, you know how to do it. Just build a new control that inherits from an existing control, add some custom members, and use it. Create a project with all the “enhanced” controls and use them regularly in your projects. All you have to do is add a reference to the DLL that implements the control in a new project, just like reusing a custom class.
Classifying the Control’s Properties
Let’s go back to our FocusedTextBox control — there are some loose ends to take care of. First, we must specify the category in the Properties window under which each custom property appears. By default, all the properties you add to a custom control are displayed in the Misc section of the Properties window. To specify that a property be displayed in a different section, use the Category attribute of the Property procedure. As you will see, properties have other attributes too, which you can set in your code as you design the control.
Properties have attributes, which appear in front of the property name and are enclosed in a pair of angle brackets. All attributes are members of the System.ComponentModel class, and you must import this class to the module that contains the control’s code. The following attribute declaration in front of the property’s name determines the category of the Properties window in which the specific property will appear:
<Category("Appearance")> Public Property ...
Code language: PHP (php)
If none of the existing categories suits a specific property, you can create a new category in the Properties window by specifying its name in the Category attribute. If you have a few properties that should appear in a section called Conditional, insert the following attribute in front of the declarations of the corresponding properties:
<Category("Conditional")> Public Property ...
Code language: PHP (php)
When this control is selected, the Conditional section will appear in the Properties window, and all the properties with this attribute under it. Another attribute is the Description attribute, which determines the property’s description that appears at the bottom of the Properties window when the property is selected. To specify multiple attributes, separate them with commas, as shown here:
<Description("Indicates whether the control can be left blank"),
Category("Appearance")>
Property Mandatory() As Boolean
{ the property procedure's code }
End Property
Code language: PHP (php)
The most important attribute is the DefaultValue attribute, which determines the property’s default (initial) value. The DefaultValue attribute must be followed by the default value in parentheses:
<Description("Indicates whether the control can be left blank")
Category("Appearance"), DefaultValue(False)>
Property Mandatory() As Boolean
{ the property procedure's code }
Code language: PHP (php)
Some attributes apply to the class that implements the custom controls. The DefaultProperty and DefaultEvent attributes determine the control’s default property and event. To specify that Mandatory is the default property of the FocusedTextBox control, replace the class declaration with the following:
<DefaultProperty("Mandatory")> Public Class FocusedTextBox
Code language: PHP (php)
Events are discussed later in the chapter, but you already know how to raise an event from within a class. Raising an event from within a control’s code is quite similar. Open the FocusedTextBox project, examine its code, and experiment with new properties and methods. As you may have noticed, all custom controls appear in the Toolbox with the same icon. You can specify the icon to appear in the Toolbox with the ToolboxBitmap attribute, whose syntax is the following, where imagepath is a string with the absolute path to a 16 × 16 pixel bitmap:
<ToolboxBitmap(imagepath)> Public Class FocusedTextBox
Code language: PHP (php)
The bitmap is actually stored in the control’s DLL and need not be distributed along with the control.
Now we’re ready to move on to something more interesting. This time, we’ll build a control that combines the functionality of several controls, which is another common scenario. You will literally design its visible interface by dropping controls on it, just like designing the visible interface of a Windows form.