Introduction
Often, it is necessary to control the input of a textbox to maintain the successful functioning of an application, particularly those involving accounting and databases. This textbox controls what the user can type into it. It does this by validating the input character on KeyPress
. It has nine modes that are all useful in different situations and can be changed via the ValidationFormat
property in design or runtime.
As opposed to other validating textboxes, this is all done on KeyPress
. So, there is no possible way that the user can input the wrong data. Although it has elements similar to the masked textbox, it provides functionality for alphanumeric, decimal, currency and, uniquely, capitalisation. Capitalisation is useful for when the user inputs their name into your fields. This way, when this information is stored, it is in the correct format in case the use has been forgotten.
Note: This was made in Visual Studio 2005 on Windows XP using .NET Framework 2.0.
Features
9 ValidationFormat Modes
None
: Allows any characters.
Alphabetical
: Allows only letters.
Numeric
: Allows only numbers.
Alphanumeric
: Allows only letters and numbers.
Decimal
: Allows numbers and one decimal point. Accommodates for locality and difference in currency symbols and separator characters.
CapitaliseEachWordAlphabetical
: Allows only letters and capitalises the first letter of each word.
CapitaliseEachWordAlphanumeric
: Allows only letters and numbers and capitalises the first letter of each word.
CapitaliseEachWordAll
: Allows any characters and capitalises the first letter of each word.
Currency
: Allows only numbers, one currency symbol, one decimal separator and unlimited group separators. Accommodates for locality and difference in currency symbols and separator characters.
UpperCaseAlphabetical
: Allows only upper case letters; letters typed in lower case will be converted to upper case.
UpperCaseAlphabetical
: Allows only upper case letters and numbers; letters typed in lower case will be converted to upper case.
LowerCaseAlphabetical
: Allows only lower case letters; letters typed in upper case will be converted to lower case.
LowerCaseAlphabetical
: Allows only lower case letters and numbers; letters typed in upper case will be converted to lower case.
Validation on KeyPress, Leave and TextChanged
The validation of this control is done in 3 phases. The first is on the KeyPress
event. If the user types a key that is not allowed by ValidationFormat
, the key is simply rejected. The second phase of validation occurs on the Leave
event. When the textbox loses focus, it checks that the contents of the textbox are correct in the unlikely event of the introduction of unwanted characters. In the third phase, the control validates on the TextChanged
event. This final phase is enacted in the event that the user performs a paste in the textbox.
New Properties
This text box has five new properties compared to the standard textbox and all have a separate role in the validation. The first new property is, of course, the ValidationFormat
property. This allows the designer to select what format they want their textbox in, whether it be Numeric
, Alphabetical
or any of the other modes.
The second new property is the ValidInput
property. At OnLeave
or TextChanged
validation, if some form of invalid data is entered into the textbox, the InvalidInput
property is set to false. This lets the designer know when there is invalid data.
The third new property is the AllowNull
property. If this is set to false, then if the textbox is empty or becomes empty, the ValidInput
property is set to false. This lets the designer know when there is a problem with the data.
The fourth new property is the DisplayTickOnValid
property. As opposed to the normal error displaying an icon only when the user gets it wrong, this textbox displays an icon when the user gets it right as well, but only if you want it to.
The fifth new property is the ErrorMessage
property, which will be discussed in the next section.
Everyone Knows When There's a Problem
I felt that one important thing when designing this was having not only the designer know when the textbox throws an error, but also letting the user know. To allow this, I added ErrorProvider
to the textbox. When there is a problem with validation, ErrorProvider
is set to display with an attached error, i.e. the tooltip that shows up over the error icon. The textbox then sets its ValidInput
property to false, letting the designer know that there is a problem. It also sets its ErrorMessage
property to match the error associated with ErrorProvider
. There are 3 benefits to doing all of this:
- The user knows when there is a problem, allowing the user to correct it.
- The textbox indicates when there is a problem, allowing features in the program to take the correct action such as disabling a save button, etc.
- The program can access the associated error and display it to the user, letting the user know what is wrong.
Events
Associated with each of the new properties is a new event. Each new property has an associated PropertyChanged
event. This is useful because designers can incorporate code that can:
- Allow them to take action when there is an error.
- Allow properties to be changed at runtime and have available reactions to those changes.
- Display, to the user, an error message when
ErrorMessage
is changed.
Using the Code
The code is simple, mostly. It is just a matter of compiling the control into a DLL and adding that to your toolbox. Then you can use it in any application you want. Here's how to add it to your toolbox:
- Compile the control.
- Right click the Toolbox -> Choose Items -> Browse for the DLL -> Add it and Apply -> Use the control.
The most useful part about this control, however, is the new ValidInput
property I have added. When the textbox loses focus, it verifies that its content is valid by running a check against its current ValidationFormat
. If the check returns a value specifying that the input is not valid, the ValidInput
property is set to False
. When the user goes to continue or commit the data, your program can check the textboxes. It sees if they are all valid and allows or disallows continuation. In addition to this, the control includes an in-built ErrorProvider
that will show the user that their input is invalid, giving them a chance to change it.
The Code (or Parts of It)
Declarations Regarding Globalization
Imports System.Globalization.NumberFormatInfo
Dim DSep As String =
CurrentInfo.NumberDecimalSeparator
Dim GSep As String =
CurrentInfo.NumberGroupSeparator
Dim CSym As String =
CurrentInfo.CurrencySymbol
Alphabetical
If Char.IsLetter(e.Keychar) = False Then
e.Handled = True
End If
Numeric
If Char.IsNumber(e.Keychar) = False Then
e.Handled = True
End If
Alphanumeric
If Char.IsLetterorDigit(e.Keychar) = False Then
e.Handled = True
End If
Decimal
If Char.IsNumber(e.KeyChar) = False Then
If e.KeyChar = CChar(DSep) Then
If Me.Text.Contains(DSep) Then
e.Handled = True
End If
Else
e.Handled = True
End If
End If
Checking Allow Null and Acting Appropriately
This is if the text property of the textbox is null.
If Me.AllowNull = True Then
Valid()
Else
Me.InvalidErrorProvider.SetError(Me,
"Invalid Input: This textbox must not be empty.")
Invalid()
End If
Private Sub Valid()
Me.InvalidErrorProvider.Clear()
Me.ErrorMessage = Nothing
Me.ValidInput = True
End Sub
Private Sub Invalid()
Me.ErrorMessage = Me.InvalidErrorProvider.GetError(Me)
Me.ValidInput = False
End Sub
The rest of the code is far too long to post in one large block.
Points of Interest
Capitalising was the most difficult part to get right, as there are so many variables. If the user decides to backspace, it has to check if it needs to capitalise. Then it has to capitalise the first letter and check -- in some instances -- if it is even a letter. Co-ordinating all these was a bit tricky and is probably a bit messy, so feel free to tidy up the code. An interesting thing I found was that with backspace and space, there has to be an exception for the backspace and space characters because they are blocked along with special characters.
One important thing that I had to focus on, which I hadn't originally considered, was managing the currency field. In particular, I needed to consider what and how money values were entered. Because different countries use different formats for their currency, it was necessary to tap into the System.Globalization
namespace and work with the different elements it provided for allowing international compatibility. These included CurrentInfo.NumberDecimalSeparator
, CurrentInfo.NumberGroupSeparator
and CurrentInfo.CurrencySymbol
.
History
- July 3, 2007 -- Original version posted
- July 6, 2007 -- Article updated
- July 9, 2007 -- Article updated
- August 7, 2007 -- Article and download updated