locked
Validate numeric text input RRS feed

  • Question

  • I have read through the various examples and I cannot seem to find one that deals with entering a decimal point more than once. In the KeyPress event if I use the following test, only numbers or a decimal point can be entered. How do I prevent a decimal point from being entered more than once?

            If Not Char.IsDigit(e.KeyChar) And Not Char.IsControl(e.KeyChar) And Not Asc(e.KeyChar) = 46 Then             e.Handled = True

                Beep()

            End If


    Don Murray

    Wednesday, October 23, 2013 6:32 PM

Answers

  • Here is your solution, using the KeyPress event.  It will check each character as the user enters them one at a time, and only allow correct keypresses.

    	'If you need a type Double number, add a statement to accept a single decimal point.
    	Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
    		If Not Char.IsDigit(e.KeyChar) Then e.Handled = True
    		If e.KeyChar = Chr(8) Then e.Handled = False 'allow Backspace
    		If e.KeyChar = "-" And TextBox1.SelectionStart = 0 Then e.Handled = False 'allow negative number
    		If e.KeyChar = "." And TextBox1.Text.IndexOf(".") = -1 Then e.Handled = False 'allow single decimal point
    		If e.KeyChar = Chr(13) Then GetNextControl(TextBox1, True).Focus() 'Enter key moves to next control
    	End Sub

    In case the number was input from outside, then you can use the TextChanged event instead. (Don't use both).  This one will clear the textbox after the entire number was entered, if any part of the text was incorrect.

    	'TextChanged event needed for textbox in case text was input from elsewhere
    	Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
    		Dim dot As Integer, tx As String = ""
    		Dim oldtx As String = TextBox1.Text
    		For Each ch As Char In TextBox1.Text
    			If Not (Char.IsDigit(ch) Or ch = Chr(8) Or ch = Chr(13) Or _
    			 ch = "." Or TextBox1.Text.IndexOf("-") = 0) Then TextBox1.Clear()
    		Next ch
    		dot = TextBox1.Text.IndexOf(".")
    		If dot > -1 Then			'allow only 2 decimal places
    			tx = TextBox1.Text.Substring(dot + 1)
    			If tx.Length > 2 Then TextBox1.Clear()
    		End If
    	End Sub


    Solitaire


    • Edited by Solitaire Thursday, October 24, 2013 2:05 AM
    • Marked as answer by DWMEsq Thursday, October 24, 2013 12:32 PM
    Thursday, October 24, 2013 1:52 AM

All replies

  • Hi

    One way would be test the current string (is it in a textbox?) for the decimal point and if already there, disallow it, otherwise allow it. 


    Regards Les, Livingston, Scotland

    Wednesday, October 23, 2013 6:36 PM
  • What happens if the user pastes a value into the textbox?  Try using the TextChanged event handler and one of the .TryParse methods.

    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." JohnWein

    Wednesday, October 23, 2013 6:46 PM
  • Another idea is to use a custom TextBox which allows only one decimal, also look at the WindProc that handles pasting operations

    Public Class numericTextbox
       Inherits TextBox
    
       Const WM_PASTE As Integer = &H302
    
       Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
          Dim Value As String = Me.Text
          Value = Value.Remove(Me.SelectionStart, Me.SelectionLength)
          Value = Value.Insert(Me.SelectionStart, e.KeyChar)
          e.Handled = CBool(Value.LastIndexOf("-") > 0) _
             Or Not (Char.IsControl(e.KeyChar) OrElse _
             Char.IsDigit(e.KeyChar) OrElse _
             (e.KeyChar = "."c And Not Me.Text.Contains(".") Or _
             e.KeyChar = "."c And _
             Me.SelectedText.Contains(".")) OrElse (e.KeyChar = "-"c And Me.SelectionStart = 0))
          MyBase.OnKeyPress(e)
       End Sub
    
       Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
          If m.Msg = WM_PASTE Then
             Dim Value As String = Me.Text
             Value = Value.Remove(Me.SelectionStart, Me.SelectionLength)
             Value = Value.Insert(Me.SelectionStart, Clipboard.GetText)
             Dim result As Decimal = 0
             If Not Decimal.TryParse(Value, result) Then
                Return
             End If
          End If
          MyBase.WndProc(m)
       End Sub
    
    End Class
    


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem.

    Wednesday, October 23, 2013 7:12 PM
  • Using your code is an easy way to put at the end a validation using IsNumeric on the textbox.Text. That prevents in double used decimal point separator (in English a decimal point).

    Take attention to what dbasnett writes about pasted code, the nicest for the enduser is if you do both.



    Success
    Cor

    Wednesday, October 23, 2013 7:43 PM
  • Don,

    I wouldn't use anything like that. I always let them type in anything they want to, then I use the control's .Validating event to test what they've entered.

    For what it's worth...


    Please call me Frank :)

    • Proposed as answer by Armin Zingler Wednesday, October 23, 2013 7:48 PM
    Wednesday, October 23, 2013 7:44 PM
  • I use this to validate numbers and decimals in a textbox, not after the user has finished entering them.

    Option Strict On
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            For Each C As TextBox In Controls
                AddHandler C.KeyPress, AddressOf KeyBoardKeys
                AddHandler C.KeyDown, AddressOf DisallowCopyAndPaste
            Next
    
        End Sub
    
        Private Sub KeyBoardKeys(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs)
            If Char.IsPunctuation(e.KeyChar) And e.KeyChar.ToString <> "." Or Char.IsLetter(e.KeyChar) Then 'Allows only numbers, "." and some keys like delete, backspace, enter, etc in Control
                e.Handled = True
            End If
            System.Media.SystemSounds.Asterisk.Play() ' Just for the heck of it
        End Sub
    
        Private Sub DisallowCopyAndPaste(sender As Object, e As KeyEventArgs)
            If e.Control AndAlso (e.KeyCode = Keys.V OrElse e.KeyCode = Keys.C) Then e.SuppressKeyPress = True 'Disallows copy from or paste to TextBoxs
        End Sub
    
    End Class


    Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.

    Wednesday, October 23, 2013 8:06 PM
  • Here is your solution, using the KeyPress event.  It will check each character as the user enters them one at a time, and only allow correct keypresses.

    	'If you need a type Double number, add a statement to accept a single decimal point.
    	Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
    		If Not Char.IsDigit(e.KeyChar) Then e.Handled = True
    		If e.KeyChar = Chr(8) Then e.Handled = False 'allow Backspace
    		If e.KeyChar = "-" And TextBox1.SelectionStart = 0 Then e.Handled = False 'allow negative number
    		If e.KeyChar = "." And TextBox1.Text.IndexOf(".") = -1 Then e.Handled = False 'allow single decimal point
    		If e.KeyChar = Chr(13) Then GetNextControl(TextBox1, True).Focus() 'Enter key moves to next control
    	End Sub

    In case the number was input from outside, then you can use the TextChanged event instead. (Don't use both).  This one will clear the textbox after the entire number was entered, if any part of the text was incorrect.

    	'TextChanged event needed for textbox in case text was input from elsewhere
    	Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
    		Dim dot As Integer, tx As String = ""
    		Dim oldtx As String = TextBox1.Text
    		For Each ch As Char In TextBox1.Text
    			If Not (Char.IsDigit(ch) Or ch = Chr(8) Or ch = Chr(13) Or _
    			 ch = "." Or TextBox1.Text.IndexOf("-") = 0) Then TextBox1.Clear()
    		Next ch
    		dot = TextBox1.Text.IndexOf(".")
    		If dot > -1 Then			'allow only 2 decimal places
    			tx = TextBox1.Text.Substring(dot + 1)
    			If tx.Length > 2 Then TextBox1.Clear()
    		End If
    	End Sub


    Solitaire


    • Edited by Solitaire Thursday, October 24, 2013 2:05 AM
    • Marked as answer by DWMEsq Thursday, October 24, 2013 12:32 PM
    Thursday, October 24, 2013 1:52 AM
  • Thanks for all the suggestions. I think I now have some good ideas how to proceed

    Don Murray

    Thursday, October 24, 2013 12:33 PM