none
How to restrict a textbox for inputing only numbers?

    Question

  •  
     Private Sub TextBox2_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox2.KeyPress
            If Not Char.IsNumber(e.KeyChar) AndAlso Not Char.IsControl(e.KeyChar) Then
                e.Handled = True
               
         End if
        End Sub

    I use this above code to restrict the textbox only for numbers. However if I copy a text and paste in this textbox, then it is accepting.

    Do anyone know how to restrict textbox even from such non-numbers copy-paste?

    Thank you in advance

    Wednesday, March 22, 2017 8:01 PM

All replies

  • This also works to prevent copy-paste on Windows 10 (it displays a Tooltip on my OS), not sure for older OS :
      SetWindowLong(TextBox1.Handle, GWL_STYLE, GetWindowLong(TextBox1.Handle, GWL_STYLE) Or ES_NUMBER)


    • Edited by Castorix31 Wednesday, March 22, 2017 8:23 PM
    • Proposed as answer by phil chelis Wednesday, March 22, 2017 8:50 PM
    Wednesday, March 22, 2017 8:19 PM
  •  
     Private Sub TextBox2_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox2.KeyPress
            If Not Char.IsNumber(e.KeyChar) AndAlso Not Char.IsControl(e.KeyChar) Then
                e.Handled = True
               
         End if
        End Sub

    I use this above code to restrict the textbox only for numbers. However if I copy a text and paste in this textbox, then it is accepting.

    Do anyone know how to restrict textbox even from such non-numbers copy-paste?

    Thank you in advance

    My suggestion is that you don't.

    Users know how to use a Windows TextBox - let them type anything in they want - but use the .Validating event to safeguard their entry.

    Doing it that way, you can also validate that their entry (if it passes the first test of being the correct numeric type) is also in the correct range, if applicable. For example, maybe a negative number makes shouldn't be allowed, or the maximum can't be more 1000, and so on.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Wednesday, March 22, 2017 8:23 PM

  • My suggestion is that you don't.

    Users know how to use a Windows TextBox - let them type anything in they want - but use the .Validating event to safeguard their entry.

    Doing it that way, you can also validate that their entry (if it passes the first test of being the correct numeric type) is also in the correct range, if applicable. For example, maybe a negative number makes shouldn't be allowed, or the maximum can't be more 1000, and so on.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thank you for your response.

    Can you please give me a sample code for using a Validating event to handle such condition?

    Wednesday, March 22, 2017 8:33 PM

  • Thank you for your response.

    Can you please give me a sample code for using a Validating event to handle such condition?

    I was afraid you'd ask for that. ;-)

    *****

    Yes I will - bear with me a few hours as I'm at work right now, but that's a reasonable request.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Wednesday, March 22, 2017 8:35 PM
  • Can you please give me a sample code for using a Validating event to handle such condition?

    For an overview:
    https://msdn.microsoft.com/en-us/library/ms229603(v=vs.110).aspx

    For an example:
    https://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating(v=vs.110).aspx

    Wednesday, March 22, 2017 8:35 PM
  • You van do this:

    Add the little class "TextBoxFilter" in your form and add the line shown in the form load event and it will become  possible to paste in your textbox ONLY if the clipboard only contains numbers. (If the clipboard contains anything else then number, the paste will be ignored

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            TextboxPasteFilter.BlockPaste(TextBox1)
        End Sub
    
        Private Sub TextBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox1.KeyPress
            If Not Char.IsNumber(e.KeyChar) AndAlso Not Char.IsControl(e.KeyChar) Then
                e.Handled = True
            End If
        End Sub
    
    
        Class TextboxPasteFilter : Inherits NativeWindow
            Private Const WM_PASTE As Integer = &H302
            Private Sub New(Tb As TextBox)
                Me.AssignHandle(Tb.Handle)
            End Sub
            Public Shared Sub BlockPaste(TB As TextBox)
                Dim instance = New TextboxPasteFilter(TB)
            End Sub
            Protected Overrides Sub WndProc(ByRef m As Message)
                If Not m.Msg = WM_PASTE Then
                    MyBase.WndProc(m)
                Else
                    Dim Txt = Clipboard.GetText
                    If Integer.TryParse(Txt, New Integer) Then MyBase.WndProc(m)
                End If
            End Sub
        End Class
    End Class


    Luc

    Wednesday, March 22, 2017 10:13 PM

  • Thank you for your response.

    Can you please give me a sample code for using a Validating event to handle such condition?

    Tabzee,

    I set up a simple form so that you can duplicate it as I hope you will:

    Nonsensical though it is, let's set this up so that the user is to enter a quantity of cases - which has to be a whole number - and a price for each case which will be a decimal type (for accuracy).

    Also though, let's set some limits for each of those:

    Case Quantity
         Minimum: 1
         Maximum: 50

    Price Per Case
         Minimum: 10
         Maximum: 1000

    Now the code which is long, but intentionally so:

    Option Strict On Option Explicit On Option Infer Off ' One of the cardinal rules of good programming is ' “don’t repeat yourself!”, but in the following, ' I most certainly am in the .Validating event ' handler sub. ' ' I’m doing that so that following the logic (here ' – in the forum) is more obvious; not because ' it’s a good idea. ;-) Public Class Form1 Private Const _caseQtyMinimum As Integer = 1 Private Const _caseQtyMaximum As Integer = 50 Private Const _sellPriceMinimum As Decimal = 10 Private Const _sellPriceMaximum As Decimal = 1000 Private ep As New ErrorProvider Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load btn_ShowExtendedPrice.Enabled = False End Sub Private Sub _ TextBoxTextChanged(sender As System.Object, _ e As System.EventArgs) _ Handles TextBox_Qty.TextChanged, _ TextBox_PricePer.TextChanged ep.Clear() If TextBox_Qty.Text.Trim.Length > 0 AndAlso _ TextBox_PricePer.Text.Trim.Length > 0 Then btn_ShowExtendedPrice.Enabled = True Else btn_ShowExtendedPrice.Enabled = False End If End Sub Private Sub _ TextBoxValidating(sender As Object, _ e As System.ComponentModel.CancelEventArgs) _ Handles TextBox_Qty.Validating, _ TextBox_PricePer.Validating Dim tb As TextBox = DirectCast(sender, TextBox) If tb.Text.Trim.Length > 0 Then Dim sb As New System.Text.StringBuilder Select Case tb.Name Case "TextBox_Qty" Dim tempVal As Integer = 0 If Integer.TryParse(tb.Text, tempVal) Then ' It's valid, so now let's check the actual value ' and make sure that it's within the limits of ' minimum and maximum set by the class-scoped ' variables (that you see at the top of the code). ' ' Before reading this part of the code, know this ' please: ' ' The TryParse method is a great one: ' ' IF it can be converted (cast) to the correct ' type, then it does it and the method will return ' a boolean True. In the following, you’ll see ' that I’m testing what it returns and telling it ' what to do either way. ' ' If it CANNOT be converted to the correct type – ' an integer in this case – then it doesn't throw ' an exception, which is good, but the onus is on ' us to handle this situation (shown below if it ' returns boolean False). If tempVal < _caseQtyMinimum Then sb.AppendLine("The minimum case quantity that") sb.AppendLine(String.Format("you can assign is {0:n0}.", _caseQtyMinimum)) sb.AppendLine() sb.AppendLine("Please re-enter the value or clear") sb.AppendLine("the text area entirely in order") sb.AppendLine("to continue.") ep.SetError(tb, sb.ToString) e.Cancel = True btn_ShowExtendedPrice.Enabled = False ElseIf tempVal > _caseQtyMaximum Then sb.AppendLine("The maximum case quantity that") sb.AppendLine(String.Format("you can assign is {0:n0}.", _caseQtyMaximum)) sb.AppendLine() sb.AppendLine("Please re-enter the value or clear") sb.AppendLine("the text area entirely in order") sb.AppendLine("to continue.") ep.SetError(tb, sb.ToString) e.Cancel = True btn_ShowExtendedPrice.Enabled = False End If Else ' It's not a valid entry: sb.AppendLine("The value entered is not a valid") sb.AppendLine("entry for the case quantity.") sb.AppendLine() sb.AppendLine("Please re-enter the value or clear") sb.AppendLine("the text area entirely in order") sb.AppendLine("to continue.") ep.SetError(tb, sb.ToString) e.Cancel = True btn_ShowExtendedPrice.Enabled = False End If Case "TextBox_PricePer" Dim tempVal As Decimal = 0 If Decimal.TryParse(tb.Text, tempVal) Then If tempVal < _sellPriceMinimum Then sb.AppendLine("The minimum price per case that") sb.AppendLine(String.Format("you can assign is {0:c0}.", _sellPriceMinimum)) sb.AppendLine() sb.AppendLine("Please re-enter the value or clear") sb.AppendLine("the text area entirely in order") sb.AppendLine("to continue.") ep.SetError(tb, sb.ToString) e.Cancel = True btn_ShowExtendedPrice.Enabled = False ElseIf tempVal > _sellPriceMaximum Then sb.AppendLine("The maximum price per case that") sb.AppendLine(String.Format("you can assign is {0:c0}.", _sellPriceMaximum)) sb.AppendLine() sb.AppendLine("Please re-enter the value or clear") sb.AppendLine("the text area entirely in order") sb.AppendLine("to continue.") ep.SetError(tb, sb.ToString) e.Cancel = True btn_ShowExtendedPrice.Enabled = False End If Else sb.AppendLine("The value entered is not a valid") sb.AppendLine("entry for the price.") sb.AppendLine() sb.AppendLine("Please re-enter the value or clear") sb.AppendLine("the text area entirely in order") sb.AppendLine("to continue.") ep.SetError(tb, sb.ToString) e.Cancel = True btn_ShowExtendedPrice.Enabled = False End If End Select End If End Sub Private Sub _ btn_ShowExtendedPrice_Click(sender As System.Object, _ e As System.EventArgs) _ Handles btn_ShowExtendedPrice.Click ' Because the values have been validated, I can ' now safely convert them to their appropriate ' types (integer for case quantity and decimal for ' the price per case) and know that the conversion ' will work:: Dim caseQty As Integer = CInt(TextBox_Qty.Text) Dim pricePer As Decimal = CDec(TextBox_PricePer.Text) Dim total As Decimal = caseQty * pricePer MessageBox.Show("Total: " & total.ToString("c2"), "Result") End Sub End Class


    I'll step through it:

    That's a lot to take in so I hope you'll duplicate it. The names of the controls are:

    • TextBox_Qty
    • TextBox_PricePer
    • btn_ShowExtendedPrice

    Following are some links to look at:

    Validating Event

    ErrorProvider Control

    TryParse (Integer, but other value types have them too)

    Give it a try and let me know your thoughts. :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Wednesday, March 22, 2017 10:40 PM
  • Hi Tabzee,
    Based on your description, You can do this with the use of Ascii integers. Put this code in the Textbox's Keypress event. e.KeyChar represents the key that's pressed. And the the built-in function Asc() converts it into its Ascii integer.

    Code:

    Private Sub TextBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox1.KeyPress
            If Asc(e.KeyChar) <> 8 Then
                If Asc(e.KeyChar) < 48 Or Asc(e.KeyChar) > 57 Then
                    e.Handled = True
                End If
            End If
    
    End Sub
    

    Best Regards,

    Cherry Bu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, March 23, 2017 6:15 AM
    Moderator
  • This one for a long time on our website

    http://www.vb-tips.com/WindowsFormsNumericTextBox.ASPX


    Success
    Cor

    Thursday, March 23, 2017 6:21 AM
  • This one for a long time on our website

    http://www.vb-tips.com/WindowsFormsNumericTextBox.ASPX



    Yes, although now ES_NUMBER does all the work (at least on Windows 10, cannot test other OS)


    • Edited by Castorix31 Thursday, March 23, 2017 6:47 AM
    Thursday, March 23, 2017 6:41 AM
  • This one for a long time on our website

    http://www.vb-tips.com/WindowsFormsNumericTextBox.ASPX



    Yes, although now ES_NUMBER does all the work (at least on Windows 10, cannot test other OS)


    Can you show it in a running way. 

    It is a part of Windows, but probably not standard in Windows Forms with VB.Net which is used by most who asks questions here and therefore I gave up asking for that. 



    Success
    Cor

    Thursday, March 23, 2017 6:59 AM
  • Can you show it in a running way. 

    It is a part of Windows, but probably not standard in Windows Forms with VB.Net which is used by most who asks questions here and therefore I gave up asking for that. 

    For example , on Form1_Load, with a TextBox1 TextBox:

    SetWindowLong(TextBox1.Handle, GWL_STYLE, GetWindowLong(TextBox1.Handle, GWL_STYLE) Or ES_NUMBER)
    with the declarations :
    Const GWL_STYLE As Integer = (-16)
    Const ES_NUMBER As Integer = &H2000	  
    	  
     <DllImport("user32.dll", SetLastError:=True)>
        Private Shared Function SetWindowLong(hWnd As IntPtr, nIndex As Integer, dwNewLong As Integer) As Integer
        End Function

      <DllImport("user32.dll", SetLastError:=True)>
        Private Shared Function GetWindowLong(hWnd As IntPtr, nIndex As Integer) As Integer
        End Function

    • Edited by Castorix31 Thursday, March 23, 2017 7:20 AM
    Thursday, March 23, 2017 7:12 AM
  • Yes this goes fine, however it is not that one line code likewise you in my perception first suggested. 


    Success
    Cor

    Thursday, March 23, 2017 7:40 AM