This is a question that seems to come up a lot in the forums:- How can I restrict the TextBox input to numerals, or only a single occurrence of a decimal point, or some other restriction?
As ever, there are several approaches. If the restriction is something basic, such as numerals only then the easy approach is to use the KeyPress event. What you can do is stop the character from appearing in the TextBox, test to see if it is allowable and, if it is, then allow it to continue.
Letters Only
To take an example which only allows letters of the alphabet, it would look like this:
Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
e.Handled = True
If e.KeyChar Like "[A-z]" Then e.Handled = False
End Sub
In this snippet, it is the e.Handled = True which blocks the input temporarily. The next line assesses whether the key press is a letter of the alphabet*, either lower or upper case, and if it is then the handled setting is reversed. This allows the key press to be passed to the TextBox display. If it fails the test, the block on this key press remains.
* Depending on your locale and keyboard, some other keys are allowed. These include symbols that are used in combination with characters in some languages, such as accents. In most cases this is the behaviour you will want.
Specific Keys
Sometimes you may want to allow certain keys. A common situation is where you will let the user use the Backspace to correct an error when inputting:
Private Sub TextBox2_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox2.KeyPress
e.Handled = True
If e.KeyChar Like "[A-z]" _
Or e.KeyChar = Chr(&H8) Then
e.Handled = False
End If
End Sub
In this case, it is the Chr(&H8) which identifies and allows the Backspace.
Numbers Only
Another common requirement is to restrict input to numerals. Of the several possible approaches, using IsNumeric is one of the most straightforward:
Private Sub TextBox3_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox3.KeyPress
e.Handled = True
If IsNumeric(e.KeyChar) Then e.Handled = False
End Sub
Sometimes that is too restrictive though. What happens if you want to allow the user to enter decimal points or (depending on their locale) commas to break up large numbers? Allowing these individual characters is simple, but there is another potential catch as we will see in a moment:
Private Sub TextBox4_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox4.KeyPress
e.Handled = True
If IsNumeric(e.KeyChar) _
Or e.KeyChar = "." _
Or e.KeyChar = "," Then
e.Handled = False
End If
End Sub
Only One Decimal Point
In most cases where users are inputting numeric values you will want to restrict them to a single decimal point. The code above will allow multiple entries. Again, there are several solutions, but the following one will usually do the job:
Private Sub TextBox5_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox5.KeyPress
e.Handled = True
If e.KeyChar <> "." Then
If IsNumeric(e.KeyChar) Then e.Handled = False '
ElseIf TextBox5.Text.Contains(".") Then
MessageBox.Show("Only one decimal point allowed")
Else
e.Handled = False
End If
End Sub
Command Keys
If you use any of the previous methods, you will be able to control the standard input keys. But there is another group of keys - Command keys - which won't be excluded by the use of the e.Handled approach. These include such keys as Home, End, Tab, and so on. You may risk alienating your users by excluding these, but there may be times when it is reasonable to do so, in which case you'll need to know how.
A good way is to intercept the message at the window level and you can do this by overriding the ProcessCmdKey function. Here's how:
Create a new class which inherits from the basic TextBox. Override the ProcessCmdKey function and test for the currently pressed key in a similar way to that used in the earlier examples. If the key is one you want to suppress then you return True and the Windows message pump will ignore it.
The following code will be all you need:
Public Class CustomTextBox
Inherits System.Windows.Forms.TextBox
Sub New()
Me.BackColor = Color.Azure
End Sub
Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
' Declare a variable of type Keys enumeration
' named keyPressed.
' Cast the msg's WParam as a KeyEnum value
' and assign it to the keyPressed variable.
Dim keyPressed As Keys = CType(msg.WParam.ToInt32(), Keys)
' Process the key that is pressed.
' If keyPressed = Keys.Home Or keyPressed = Keys.End Then Return True
If keyPressed = Keys.Tab Then Return True
' Return the Command key message
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
End Class
The light blue back color is simply to make this sub-classed TextBox look slightly different from the default one for demo purposes, but of course is not a key part of the key checking functionality. As you can see, my example blocks the Tab key. You can add or replace other keys, such as Home and End.
Multiple Options
Handling the KeyPress is fine if you only have a few TextBoxes for which you are controlling input. If there are going to be a lot of them throughout your application, or if you have different input rules for several TextBoxes, then again it may be worth your while to create your own inherited version.
The following example deals with some of the previous scenarios, but allows the input rule to be selected from an enumeration of choices. The choices used here remain basic, but of course you can expand this idea much further.
Here is the code:
Public Class RestrictedTextBox
Inherits System.Windows.Forms.TextBox
Enum RestrictionCategory
NoRestriction
NumeralsOnly
LettersOnly
AlphanumericOnly
End Enum
Private _allowedKeys As RestrictionCategory
Property AllowedKeys() As RestrictionCategory
Get
Return _allowedKeys
End Get
Set(ByVal Value As RestrictionCategory)
Select Case Value
Case 1 To 3 ' One of the enum choices
_allowedKeys = Value
Case Else ' No restriction
_allowedKeys = 0
End Select
End Set
End Property
Protected Overrides Sub OnKeyPress(ByVal e As KeyPressEventArgs)
MyBase.OnKeyPress(e)
' Test whether key is allowed, based on the current choice
' from the enum
Select Case _allowedKeys
Case 1 'Numerals only
If IsNumeric(e.KeyChar) Then
Exit Sub
Else
e.Handled = True
End If
Case 2 ' Letters Only
If e.KeyChar Like "[A-z]" Then
Exit Sub
Else
e.Handled = True
End If
Case 3 ' Alphanumeric
If e.KeyChar Like "[A-z]" _
Or IsNumeric(e.KeyChar) Then
Exit Sub
Else
e.Handled = True
End If
End Select
End Sub
End Class
The key areas are the enumeration which is called RestrictionCategory. These are automatically assigned values from 0 to 3. The Property AllowedKeys and its backing Field carry out the standard roles of a Property, the user being able to set the AllowedKeys property in code. (You could improve this by having the property appear in the Properties Window).
The core of this class is the overridden OnKeyPress method. This checks for the chosen enumeration and then either allows or applies the blocking filter to the currently pressed key. This works in a very similar way to the individual KeyPress approach used in the earlier examples.
By default, all keys will be allowed and to set the enumeration of your choice, you simply include code similar to the following somewhere appropriate in your form (I've used the Form Load event for my example):
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.RestrictedTextBox1.AllowedKeys = RestrictedTextBox.RestrictionCategory.NumeralsOnly
End Sub
Summary
I think that a combination or extension of any of the above approaches will enable you to control exactly what you will allow the user to input into a TextBox.