The MaskedTextBox Control
The MaskedTextBox control provides restricted data input as well as formatted data output. This control supplies visual cues about the type of data being entered or displayed. It can be useful in data entry applications in that it can prevent the user from entering invalid data.
In my opinion, the masked textbox control is suitable for the entry of some types of data items, but inadequate for others.
The masked textbox control is GOOD for items that are fixed in length with a defined format, such as Social Security Numbers, phone numbers, zip codes; generally anything with a fixed number of digits and/or letters (account numbers, state abbreviations, etc.).
It is "so-so" for dates (you must enter all digits and it does not validate the correctness of the date).
The masked textbox control is BAD for numeric items with a decimal point where the number of digits before and/or after the decimal point can vary (such money amounts, rates, measurements, etc.). This is because the control will not right-align the value nor line up the decimal point as you enter the value. For these types of numeric values, you are better off using the standard TextBox control and monitoring the user's input "manually" with the KeyPress event.
The MaskedTextbox control can be found in the "Common Controls" section of the Toolbox: |
|
The Mask Property
The Mask property is the "heart" of the MaskedTextBox control. With it, you define the pattern of the data item to be entered into the control. The following masking elements (characters) can be used to set the Mask property:
Masking Element |
Description |
0 |
Digit, required. Only the digits 0 through 9 can be entered in this position. |
9 |
Digit or space, optional. |
# |
Digit or space, optional. Plus (+) and minus (-) signs are allowed. |
L |
Letter, required. Restricts input to the ASCII letters a-z and A-Z. |
? |
Letter, optional. Restricts input to the ASCII letters a-z and A-Z. |
& |
Character, required. If the AsciiOnly property is set to true, this mask element behaves like the "L" element. |
C |
Character, optional. Any non-control character. If the AsciiOnly property is set to true, this mask element behaves like the "?" element. |
A |
Alphanumeric, required. If the AsciiOnly property is set to true, the only characters it will accept are the ASCII letters a-z and A-Z. This mask element behaves like the "a" element. |
a |
Alphanumeric, optional. If the AsciiOnly property is set to true, the only characters it will accept are the ASCII letters a-z and A-Z. This mask element behaves like the "A" element. |
. |
Decimal placeholder. The actual display character depends on the computer's International Settings. |
, |
Thousands placeholder. The actual display character depends on the computer's International Settings. |
: |
Time separator. The actual display character depends on the computer's International Settings. |
/ |
Date separator. The actual display character depends on the computer's International Settings. |
$ |
Currency symbol. The actual display character depends on the computer's International Settings. |
< |
Shift down. Converts all characters that follow to lowercase. |
> |
Shift up. Converts all characters that follow to uppercase. |
| |
Disable a previous shift up or shift down. |
\ |
Escape. Escapes a mask character, turning it into a literal. "\\" is the escape sequence for a backslash. |
All other characters |
Literals. All non-mask elements will appear as themselves. Literals always occupy a static position in the mask at run time, and cannot be moved or deleted by the user. |
The TextMaskFormat Property
The TextMaskFormat property specifies whether or not prompt characters and/or other literal characters are included in the Text property (the default prompt character is the underscore). The possible values for the TextMaskFormat property are:
ExcludePromptAndLiterals
IncludePrompt
IncludeLiterals
IncludePromptAndLiterals
For example, if MaskedTextBox1 specified a Mask of "###-##-####" and the user entered "123121234", the control would display "123-12-1234". If TextMaskFormat property is set to IncludePromptAndLiterals, then the value of MaskedTextBox1.Text would be 123-12-1234, and Len(MaskedTextBox.Text) would be 11. If TextMaskFormat is set to ExcludePromptAndLiterals, then the value of MaskedEdBox1.Text would be 123121234, and Len(MaskedEdBox.Text) would be 9. In most cases, it is appropriate to set the TextMaskFormat property to ExcludePromptAndLiterals – otherwise, extra logic may be needed to parse out the actual value that the user entered.
MaskedTextBox Control Demo Program
The demo program presents the user with a form containing various input fields (MaskedTextBox boxes), as shown below:
When the user fills in the fields and clicks the Process button, the application validates the entries and reports the results in the multi-line textbox at the bottom of the screen:
Clicking the Pre-Fill button populates the MaskedTextBox boxes with predetermined values (this demonstrates how to populate MaskedTextBox controls through code):
The Clear button clears the contents of the MaskedTextBox controls; the Exit button ends the program.
The form at design-time is shown below:
To build the sample application, arrange the controls on the form as shown. Set the properties of the six MaskedTextBox controls as follows:
Name |
Mask |
TextMaskFormat |
mskSSN |
###-##-#### |
ExcludePromptAndLiterals |
mskPhone |
(###) ###-#### |
ExcludePromptAndLiterals |
mskDate |
##/##/#### |
IncludeLiterals |
mskState |
>?? |
ExcludePromptAndLiterals |
mskUSZip |
####-#### |
ExcludePromptAndLiterals |
mskCanZip |
>?#? #?# |
ExcludePromptAndLiterals |
Set the properties of the four buttons as follows:
Name |
Text |
btnProcess |
Process |
btnPreFill |
Pre-Fill |
btnClear |
Clear |
btnExit |
Exit |
Set the properties of the multi-line textbox as follows:
Property |
Value |
Name |
txtResults |
MultiLine |
True |
Scrollbars |
Vertical |
ReadOnly |
True |
Code the General Declarations section as follows (there is one form-level variable, an array named mastrUSStates, which will store the 50 valid US state abbreviations):
Private mastrUSStates() As String = {"AK", "AL", "AR", "AZ", "CA", "CO", "CT", "DC", "DE", "FL", _
"GA", "HI", "IA", "ID", "IL", "IN", "KS", "KY", "LA", "MA", _
"MD", "ME", "MI", "MN", "MO", "MS", "MT", "NC", "ND", "NE", _
"NH", "NJ", "NM", "NV", "NY", "OH", "OK", "OR", "PA", "RI", _
"SC", "SD", "TN", "TX", "UT", "VA", "VT", "WA", "WI", "WV", "WY"}
Code the btnProcess_Click event as follows. Note that the tests for the lengths of the Text property of all the MaskedTextBox controls except for the mskDate control test for the length of the item excluding the mask characters - because the TextMaskFormat property for those was set to ExcludePromptAndLiterals. The length test for mskDate is 10 rather than 8 because the TextMaskFormat property for that control is set to IncludeLiterals.
Private Sub btnProcess_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles btnProcess.Click
If Len(mskSSN.Text) = 9 Then
DisplayMessage("SSN is OK.")
Else
DisplayMessage("SSN is missing or incomplete.")
End If
If Len(mskPhone.Text) = 10 Then
DisplayMessage("Telephone Number is OK.")
Else
DisplayMessage("Telephone Number is missing or incomplete.")
End If
If Len(mskDate.Text) = 10 Then
If IsDate(mskDate.Text) Then
DisplayMessage("Date is OK.")
Else
DisplayMessage("Date is invalid.")
End If
Else
DisplayMessage("Full date in MM/DD/YYYY format is required.")
End If
If ValidState() Then
DisplayMessage("U.S. State is OK.")
Else
DisplayMessage("U.S. State is invalid.")
End If
If Len(mskUSZip.Text) = 5 Or Len(mskUSZip.Text) = 9 Then
DisplayMessage("U.S. Zip is OK.")
Else
DisplayMessage("U.S. Zip is missing or incomplete.")
End If
If Len(mskCanZip.Text) = 6 Then
DisplayMessage("Canadian Zip is OK.")
Else
DisplayMessage("Canadian Zip is missing or incomplete.")
End If
End Sub
Code the btnPreFill_Click event as follows. Once again, the TextMaskFormat issue comes into play. Note that we are assigning "raw" data to each of the MaskedTextBox controls except for mskDate, where the slashes are included. When TextMaskFormat is set to IncludeLiterals, the data assigned to the control must match the mask - otherwise, an error will occur.
Private Sub btnPreFill_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles btnPreFill.Click
mskSSN.Text = "123121234"
mskPhone.Text = "1112223333"
mskDate.Text = FormatDateTime(Date.Today, DateFormat.ShortDate)
mskState.Text = "WV"
mskUSZip.Text = "123451234"
mskCanZip.Text = "R3C0V8"
txtResults.Text = ""
End Sub
Code the btnClear_Click event as follows. Here, the contents of the MaskedTextBox controls are cleared by assigning the zero-length string ("") to each control. However, for the mskDate control, where the TextMaskFormat property is set to IncludeLiterals, a special technique is required. We must first clear the Mask property, then clear the Text property. After that is done, we can reset the Mask property.
Private Sub btnClear_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles btnClear.Click
mskSSN.Text = ""
mskPhone.Text = ""
mskDate.Mask = ""
mskDate.Text = ""
mskDate.Mask = "##/##/####"
mskState.Text = ""
mskUSZip.Text = ""
mskCanZip.Text = ""
txtResults.Text = ""
mskSSN.Focus()
End Sub
Code the btnExit_Click event as follows to end the program.
Private Sub btnExit_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles btnExit.Click
Me.Close()
End Sub
Code the DisplayMessage Sub as follows. This Sub is used to build the information that appears in the multi-line textbox on the lower half of the form.
Private Sub DisplayMessage(ByRef pstrMsg As String)
txtResults.Text = txtResults.Text & vbNewLine & pstrMsg
End Sub
Code the ValidState function. This function checks the user's entry in the mskState control against the array of valid US states to determine if a valid state was entered.
Private Function ValidState() As Boolean
Dim intX As Integer
For intX = 0 To UBound(mastrUSStates)
If mskState.Text = mastrUSStates(intX) Then
Return True
Exit For
End If
Next
Return False
End Function
End Class
Download the project files for this sample application here.