3.5. Validate Input While the User Types
Visual Basic 6 and Access both provide developers with masked editing controls: text input controls that automatically format your input as you type it in based on a specific mask. For example, if you type 1234567890 into a masked input control that uses a telephone-number mask, the number is displayed as the string (123) 456-7890.
Note: VB 6 programmers accustomed to the ActiveX MaskedEdit control were disappointed to find . NET did not include a replacement. In . NET 2.0, the new MaskedTextBox fills the gap.
Masked input controls not only improve the presentation of certain valuesthey also prevent errors. Choosing the right mask ensures that certain characters will be rejected outright (for example, a telephone- number mask will not accept letters). Masked input controls also neatly avoid canonicalization errors, which occur when there is more than one way of representing the same information. For example, with the telephone number mask, the user will immediately realize that an area code is required, even if you don't specifically explain this requirement.
3.5.1. How do I do that?
.NET 2.0 includes a new control named MaskedTextBox that extends the TextBox control. Once you've added a MaskedTextBox to a form, you can set the mask in two ways:
To set a mask, click the MaskedTextBox smart tag and select Set Mask. The Input Mask dialog box appears, with a list of commonly used masks, including masks for phone numbers, zip codes, dates, and so on. When you select a mask from the list, the mask is displayed in the Mask text box. You can now customize the mask. You can also try the mask out using the Try It text box, as shown in Figure 3-7.
Figure 3-7. Selecting a mask for the MaskedTextBox
Note: Thanks to the wonders of COM Interop, it's still possible to use the VB 6 MaskedEdit control in . NET. However, the . NET MaskedTextBox control improves on several limitations and quirks in the MaskedEdit control, so it's still superior.
The mask you choose will be stored in the MaskTextBox.Mask property. Once you've chosen a mask, it will be applied whenever the user types in the MaskedTextBox. If you want to respond to user mistakes (like invalid characters) to provide more information, you can respond to the MaskInputRejected event.
If you want to build a custom mask, you need to understand a little more about how masking works. Essentially, a mask is built out of two types of characters: placeholders, which designate where the user must supply a character; and literals, which are used to format the value. For example, in the phone number mask (999)-000-000, the hyphens and brackets are literals. These characters are always present and can't be deleted, modified, or moved by the user. The number 0 is a placeholder that represents any number character, while the number 9 is a placeholder that represents an optional numeric character.
Table 3-1 lists and explains all the characters you can use to create a mask. You can use this as a reference to build your own masks.
Finally, there are a few more properties that the MaskedTextBox provides (and you might want to take advantage of). These include:
3.5.2. What about...
...using masked editing in other input controls? It is possible, but not easy. The MaskedTextBox relies on a special MaskedEditProvider class in the System.ComponentModel namespace.
To create a different type of masked control, you need to create a custom control that uses the MaskedEditProvider internally. When your control receives a key press, you need to determine the attempted action and pass it on to the MaskedEditProvider using methods like Add( ), Insert( ), Remove( ), and Replace( ). Then, you can retrieve the new display value by calling MaskedEditProvider.ToDisplayString( ), and refresh your custom control appropriately. The hard part is handling all of this low-level editing without causing flicker or losing the user's place in the input string. For more information, you can refer to the full example that's included with the downloadable code in the MaskedEditing project.