Implementing a Custom Windows Control

As mentioned earlier, components do not have a visual aspect at runtime; controls do. You can create a custom control by defining a new control that inherits from System.Windows.Forms.Control or an existing control, like the TextBox control. If you want to create a brand new control, inherit from the Control class. Intuitively it will be easier to create a control if you inherit from one that already has much of the functionality you need.

Defining a Regular Expression TextBox Control

You may use a Validating event to write code to validate the value of a TextBox control. Using an event handler is convenient for general purpose validation; however, if you find yourself using a specific kind of validation repeatedly, you can save time by incorporating that validation into a custom TextBox control.

Regular expressions represent a powerful means of performing pattern matching of a complex nature. The RegexTextBox control incorporates the power of regular expressions with TextBox validation.

Listing 9.3 defines a custom TextBox control that has a Pattern property. The Pattern property represents a regular expression. Assigning a regular expression string to RegexTextBox will validate the input against the regular expression. This control is a great building block for specifically typed TextBox controls. (The source code for RegexTextBox is contained in RegexTextBox.sln .)

By convention in .NET, methods raise events, and those methods have an On prefix. For example, a Validating event is raised by an OnValidating method. Thus, if you generalize a control with the Validating event and you want to extend the validation behavior, you will override the OnValidating event. Listing 9.3 demonstrates how to add a new property to a custom control and override a behavioral method.

Listing 9.3 Implementing the RegexTextBox Control
 1:  Imports System.ComponentModel 2:  Imports System.Text.RegularExpressions 3: 4:  Public Class RegexTextBox 5:    Inherits TextBox 6: 7:    Private FPattern As String 8: 9:    Public Property Pattern() As String 10:   Get 11:     Return FPattern 12:   End Get 13:   Set(ByVal Value As String) 14:     FPattern = Value 15:   End Set 16:   End Property 17: 18:   Protected Overrides Sub OnValidating( _ 19:     ByVal e As CancelEventArgs) 20:     If (Regex.IsMatch(Text, FPattern) Or _ 21:       FPattern = String.Empty) Then 22:       e.Cancel = False 23:       MyBase.OnValidating(e) 24:     Else 25:       DoValidatingError(e) 26:     End If 27:   End Sub 28: 29:   Private Sub DoValidatingError(ByVal e As CancelEventArgs) 30:     Const Message As String = _ 31:       "Text does not match pattern expression {0}" 32: 33:     If (MessageBox.Show(String.Format(Message, FPattern), _ 34:       "Properties Window", MessageBoxButtons.OKCancel, _ 35:       MessageBoxIcon.Exclamation) = DialogResult.OK) Then 36:       e.Cancel = False 37:       MyBase.OnValidating(e) 38:     Else 39:       e.Cancel = True 40:       MyBase.ResetText() 41:     End If 42: 43:   End Sub 44: 45: End Class 

The private field FPattern holds the regular expression, and the public property Pattern is used to get and set the value of the underlying field. The OnValidating method overrides the inherited OnValidating method (see lines 18 through 27). Recall that we are overriding the behavior of a method that raises an event. To make sure that the original behavior happens we need to invoke the inherited method. I elected to invoke the inherited method only on the condition that my custom validation occurs. As a general rule, always invoke the base behavior. However, you can reserve the right to break from conventional wisdom as long as you are aware of possible adverse consequences (see Note below).

Finally, lines 29 through 43 enact some simple gyrations to let the RegexTextBox user decide whether to continue with an invalid value in the TextBox control if the input value does not match the regular expression pattern.

NOTE

As a rule, programmers using a class should concern themselves not with how a class is implemented but with how a class works. After all, this is the reason we have access modifiers like Public , Private , and Protected . Users should worry about only public details. Alternatively, generalizers ”that is, people who inherit from and extend existing classes ”must concern themselves with the implementation details of public and protected members . Thus, Microsoft should release the source code to the base class libraries (BCLs), including the source code for ADO.NET and controls like TextBox . Releasing Rotor is a good first step, but Microsoft should follow Borland's lead and provide us with the source code for controls too. Clearly Borland suffered no deleterious effects for releasing its Visual Control Library (VCL); in fact, Borland reaped the benefit of a cottage industry of component builders. Borland's problems have never been related to its technology.

Having said all that, it is possible that conditionally calling the inherited OnValidating method may result in adverse side effects. Without the source code to TextBox it may be impossible to know for sure. If you experience problems with the conditional behavior of RegexTextBox , let me know at pkimmel@softconcepts.com.

Testing the Custom Component

Testing custom controls before inserting them into the Toolbox is as easy as declaring and creating an instance of the control. Listing 9.4 demonstrates how we might test the RegexTextBox control before incorporation into the Toolbox and general dissemination . Because the TextBox control has a Windows handle ” hWnd ”and needs to receive messages like WM_PAINT , it is essential that we add the programmatically created RegexTextBox to the form's Controls collection.

Listing 9.4 Declaring and Creating an Instance of RegexTextBox for Testing
 1:  Public Class Form1 2:      Inherits System.Windows.Forms.Form 3: 4:  [ Windows Form Designer generated code ] 5: 6:    Private RegexTextBox1 As RegexTextBox 7: 8:    Private Sub Form1_Load(ByVal sender As System.Object, _ 9:      ByVal e As System.EventArgs) Handles MyBase.Load 10: 11:     RegexTextBox1 = New RegexTextBox() 12:     RegexTextBox1.Pattern = "^\d+$" 13:     Controls.Add(RegexTextBox1) 14: 15:   End Sub 16: End Class 

Line 13 demonstrates the step of adding the RegexTextBox1 instance to the form's Controls collection. Line 12 shows a regular expression that matches a string containing one or more digits. The caret ( ^ ) and dollar sign ( $ ) indicate expression boundaries. The result is that the text must be a contiguous string of digits with no preceding white space. If the string does not match, a message box appears to alert the user (Figure 9.1).

Figure 9.1. The RegexTextBox control will display a message box similar to the one shown if the pattern does not match the input text.

graphics/09fig01.gif

Regular expressions represent an entire language themselves. The regular expression language in .NET is designed to be compatible with Perl 5. Regular Expressions with .NET by Dan Appleman [2002] is an excellent 75 page e-book on .NET regular expressions.



Visual Basic. NET Power Coding
Visual Basic(R) .NET Power Coding
ISBN: 0672324075
EAN: 2147483647
Year: 2005
Pages: 215
Authors: Paul Kimmel

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net