Mgfranz
Mgfranz

Reputation: 41

Event not Firing on First KeyPress

I am trying to call a Sub from within the keyPress event in a textBox, the problem is that the Sub will not get called until the second keyPress, at that time the keyPress processes the first key entered, if a third keyPress is done the sub will process the second keyPress and so on... Here is an image;

Form KeyPress

And here is my code;

Private nonNumberEntered As Boolean = False

Private Sub txtAmount_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles txtAmount.KeyPress
    'Only allowed characters
    Dim allowedChars As String = "0123456789."
    nonNumberEntered = False
    If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
        If e.KeyChar <> ControlChars.Back Then
            If allowedChars.IndexOf(e.KeyChar) = -1 Then
                ' Invalid Character, notify clear and return
                MsgBox("Numbers only", MsgBoxStyle.Exclamation)
                txtAmount.Text = ""
                txtAmount.Focus()
                nonNumberEntered = True
            End If
        End If
    End If
    'If shift key was pressed, it's not a number.
    If Control.ModifierKeys = Keys.Shift Then
        nonNumberEntered = True
    End If
    'Call the function to create a text line out of the numbers
    'Regex to ensure the string contains numbers
    Dim re As New Text.RegularExpressions.Regex("\d")
    If re.IsMatch(txtAmount.Text) Then
        If nonNumberEntered = False Then
            Dim newNum = txtAmount.Text.Trim
            'If there are any leading weird . in the string
            newNum = newNum.TrimStart(".")
            Dim newStr As String
            'Build the array
            Dim newDec As String() = newNum.Split(New Char() {"."c})
            If newNum.Contains(".") Then
                newStr = NumberToText(newDec(0))
                lblResult.Text = newStr & " Dollars and " & newDec(1) & "/100 "
            Else
                newStr = NumberToText(newDec(0))
                lblResult.Text = newStr & " Dollars and 00/100 "
            End If

        End If
    End If
End Sub

Any ideas?

Upvotes: 0

Views: 514

Answers (3)

Mgfranz
Mgfranz

Reputation: 41

Ok Chris, you were close. What I needed to do was set e.KeyChar = "" and then trap the and in KeyPress. So here is my final solution that is working as intended.

Private Sub cbCheckAmount_KeyPress(sender As Object, e As KeyPressEventArgs) Handles cbCheckAmount.KeyPress
    'Only allowed characters
    Dim allowedChars As String = "0123456789."
    If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
        If e.KeyChar <> ChrW(Keys.Return) Or e.KeyChar <> ChrW(Keys.Tab) Then
            If e.KeyChar <> ControlChars.Back Or e.KeyChar <> ControlChars.Tab Then
                If allowedChars.IndexOf(e.KeyChar) = -1 Then
                    ' Invalid Character, notify clear and return
                    nonNumberEntered = True    'Set to True to 'swallow' the keypress and prevent the TextChanged event from firing.
                    MsgBox("Numbers only", MsgBoxStyle.Exclamation)
                    cbCheckAmount.Text = ""
                    cbCheckAmount.Focus()
                    lblTotalText.Text = ""
                    e.KeyChar = ""
                    nonNumberEntered = False
                End If
            End If
        End If
    End If

    'If shift key was pressed, it's not a number.
    If Control.ModifierKeys = Keys.Shift Then
        nonNumberEntered = True
        cbCheckAmount.Text = ""
        cbCheckAmount.Focus()
    End If

End Sub
Private Sub cbCheckAmount_TextChanged(sender As Object, e As EventArgs) Handles cbCheckAmount.TextChanged
    'Call the function to create a text line out of the numbers
    'Regex to ensure the string contains numbers
    Dim t As ComboBox = sender
    Dim foo As Decimal
    If nonNumberEntered = False Then
        If Decimal.TryParse(cbCheckAmount.Text, foo) Then
            'data is good
            Dim re As New Text.RegularExpressions.Regex("\d")
            If re.IsMatch(cbCheckAmount.Text) Then
                If nonNumberEntered = False Then
                    Dim newNum = cbCheckAmount.Text.Trim
                    'If there are any leading weird . in the string
                    newNum = newNum.TrimStart(".")
                    Dim newStr As String
                    'Build the array
                    Dim newDec As String() = newNum.Split(New Char() {"."c})
                    If newNum.Contains(".") Then
                        newStr = NumberToText(newDec(0))
                        lblTotalText.Text = newStr & " Dollars and " & newDec(1) & "/100 "
                    Else
                        newStr = NumberToText(newDec(0))
                        lblTotalText.Text = newStr & " Dollars and 00/100 "
                    End If
                End If
            End If
        End If
    Else
        'data is bad
        nonNumberEntered = True
        cbCheckAmount.Text = ""
        'cbCheckAmount.Focus()
        'lblTotalText.Text = ""
    End If

End Sub

Upvotes: 0

Mgfranz
Mgfranz

Reputation: 41

Here is what I am using as my solution, might be a bit of a kluge but it works;

Private nonNumberEntered As Boolean = False
Private Sub txtAmount_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtAmount.KeyPress
    'Only allowed characters
    Dim allowedChars As String = "0123456789."

    If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
        If e.KeyChar <> ControlChars.Back Then
            If allowedChars.IndexOf(e.KeyChar) = -1 Then
                ' Invalid Character, notify clear and return
                nonNumberEntered = True    'Set to True to 'swallow' the keypress and prevent the TextChanged event from firing.
                MsgBox("Numbers only", MsgBoxStyle.Exclamation)
                txtAmount.Text = ""
                txtAmount.Focus()
                lblResult.Text = ""
            End If
        End If
    End If
    'If shift key was pressed, it's not a number.
    If Control.ModifierKeys = Keys.Shift Then
        nonNumberEntered = True
        txtAmount.Text = ""
        txtAmount.Focus()
    End If
End Sub
Private Sub txtAmount_TextChanged(sender As Object, e As EventArgs) Handles txtAmount.TextChanged
    'Call the function to create a text line out of the numbers
    'Regex to ensure the string contains numbers
    Dim t As TextBox = sender
    Dim foo As Decimal
    If Decimal.TryParse(txtAmount.Text, foo) Then
        'data is good
        Dim re As New Text.RegularExpressions.Regex("\d")
        If re.IsMatch(txtAmount.Text) Then
            If nonNumberEntered = False Then
                Dim newNum = txtAmount.Text.Trim
                'If there are any leading weird . in the string
                newNum = newNum.TrimStart(".")
                Dim newStr As String
                'Build the array
                Dim newDec As String() = newNum.Split(New Char() {"."c})
                If newNum.Contains(".") Then
                    newStr = NumberToText(newDec(0))
                    lblResult.Text = newStr & " Dollars and " & newDec(1) & "/100 "
                Else
                    newStr = NumberToText(newDec(0))
                    lblResult.Text = newStr & " Dollars and 00/100 "
                End If

            End If
        End If
    Else
        'data is bad
        nonNumberEntered = False
        txtAmount.Text = ""
        txtAmount.Focus()
        lblResult.Text = ""
    End If

End Sub

Note that in the textChanged I am checking to see if the value is actually a number, if ot, clear contents and keep going. In textChanged I also allow a decimal point, but nothing else, and then I clear everything making the user start over. Simple, yet effective......

Upvotes: 0

Chris Dunaway
Chris Dunaway

Reputation: 11216

As @jmcilhinney alluded in the comments, you are trying to do too much in the KeyPress event handler. That handler should only be used to allow valid key presses and suppress invalid key presses. Whenever a valid key press is made, it is allowed to go through and then the TextChanged event handler will be called. Setting e.Handled = True will suppress the key press and the TextChanged event will not be called.

Private Sub txtAmount_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox2.KeyPress
    'Only allowed characters
    Dim allowedChars As String = "0123456789."

    If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
        If e.KeyChar <> ControlChars.Back Then
            If allowedChars.IndexOf(e.KeyChar) = -1 Then
                ' Invalid Character, notify clear and return
                e.Handled = True    'Set to True to 'swallow' the keypress and prevent the TextChanged event from firing.
                MsgBox("Numbers only", MsgBoxStyle.Exclamation)
                txtAmount.Text = ""
                txtAmount.Focus()
            End If
        End If
    End If
End Sub

Private Sub txtAmount_TextChanged(sender As Object, e As EventArgs) Handles TextBox2.TextChanged
    lblResult.Text = NumberToText(txtAmount.Text)
End Sub

Public Function NumberToText(input As String) As String
    'Convert value of amount to words here
End Function

You may also wish to look into using a MaskedTextBox which will handle the validation automatically.

Upvotes: 1

Related Questions