I am hoping this is not inappropriate to do on here if it is I apologize in advance and will let the thread die a slow agonizing death.

Here goes:
I have a little TextBox app that's supposed to only allow numeric’s positive and negative and allow 2 decimal places. I have tested it and it seems to work as intended. What I'd like is for you all to try and break it. The max characters functionality needs some work but it's not the focus of my TextBox.

Numbers_Only_Form

'K. W. 4/19/2012
'TextBox Control For
'Numerics/Money entry
'1 Decimal Point
'2 Decimal Places
'Allows The BackSpace
'Handles enter key by Moving to the Next control
'Set Max characters checked - this sets it to 4 if not checked allows 10 characters
'The button just multiplies the textbox value by 5

Public Class Form1

    Private maxSize As Boolean = False
    Private numMaxSize As Integer

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        If T1.Text <> "" Then
            If CDbl(T1.Text) > 0 Or CDbl(T1.Text) < 0 Then
                MsgBox(CDbl(T1.Text) * 5)
                T1.Clear()
            End If
        End If
        GetNextControl(Button1, False).Focus()
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'Add Handler for all the Numeric only TextBoxes on the Form
        For Each ctrl As Control In Me.Controls
            If TypeOf ctrl Is TextBox Then
                AddHandler ctrl.KeyPress, AddressOf Boxkeypress
            End If
        Next ctrl
        T1.MaxLength = 10
    End Sub

    Private Sub Boxkeypress(ByVal sender As Object, ByVal e As KeyPressEventArgs)

        Dim txt As TextBox = CType(sender, TextBox)

        If Not Char.IsDigit(e.KeyChar) Then e.Handled = True
        If e.KeyChar = "." And txt.Text.IndexOf(".") = -1 Then e.Handled = False 'allow single decimal point
        If e.KeyChar = "-" And txt.SelectionStart = 0 Then e.Handled = False 'allow negative number

        'Enter key move to next control
        If e.KeyChar = Chr(13) Then
            GetNextControl(txt, True).Focus()

            'If only a decimal point is in the box clear TextBox
            If e.KeyChar = Chr(13) And txt.Text = "." Then txt.Clear()
            Exit Sub
        End If

        Dim i As Integer = txt.Text.IndexOf(".")
        Dim len As Integer = txt.Text.Length

        'Allow only 2 Decimal places
        If Not e.Handled Then
            If i = -1 Then
                e.Handled = False
            Else
                If (len - i) > 2 Then e.Handled = True
            End If
        End If

        If e.KeyChar = Chr(8) Then e.Handled = False 'allow Backspace

    End Sub


    Private Sub chkMaxSize_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles chkMaxSize.CheckedChanged

        If chkMaxSize.Checked Then
            maxSize = True
            T1.MaxLength = 4
        Else
            maxSize = False
            T1.MaxLength = 10
        End If

    End Sub

End Class

Thanks
Krod

kRod,

First off, GREAT JOB!!!!!

Two minor things in your code.

  1. You declare and set "maxSize", but it is never used in your logic. Just delete all references to it.

  2. You use GetNextControl. This is a tricky function to use and I wish MS would reroute people to SelectNextControl as that is what most people really want anyways.

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.selectnextcontrol.aspx

Your code is fine as is, but I took the liberty to convert it to a custom control for you and to show a different style of handling the keypress event. This will also show you how to use the SelectNextControl function. Just add this class to your project and rebuild it. If you have the default settings for Visual Studio, you should see it show up in your toolbox.

Public Class kRodsTB
   Inherits System.Windows.Forms.TextBox

   Public Sub New()
      Me.MaxLength = 10
   End Sub

   Public Shadows Property MaxLength() As Int32
      Get
         Return MyBase.MaxLength
      End Get
      Set(ByVal value As Int32)
         If value = 4 OrElse value = 10 Then
            MyBase.MaxLength = value
         Else
            Throw New ArgumentException("MaxLength must be either 4 or 10")
         End If
      End Set
   End Property

   Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
      ' The "Select Case" block processes the conditions in the order written
      ' and allows (IMO) easier reading and segmentation of the conditional logic

      Select Case e.KeyChar
         Case Chr(Keys.Enter)
            'If only a decimal point is in the box clear TextBox
            If Me.TextLength = 1 And (Me.Text = "." Or Me.Text = "-") Then Me.Clear()
            Dim nextcontrol As Control = Me.Parent.GetNextControl(Me, True)

            Me.FindForm.SelectNextControl(Me, True, True, True, True)
            e.Handled = True 'stop the beep

         Case Chr(Keys.Back)
            Exit Select 'Allow backspace

         Case "."c

            If Me.Text.IndexOf(".") <> -1 Then
               e.Handled = True 'allow single decimal point
            End If

         Case "-"c
            'allow only 1 negative sign and only in the 1st position
            If Me.SelectionStart <> 0 OrElse Me.Text.IndexOf("-"c) <> -1 Then
               e.Handled = True
            End If

         Case Else

           If Char.IsNumber(e.KeyChar) Then
               Dim DecimalPosition As Integer = Me.Text.IndexOf(".")
               'Allow only 2 Decimal places
                  If DecimalPosition <> -1 AndAlso (Me.Text.Length - DecimalPosition) > 2 Then
                     e.Handled = True
                  End If
            Else
               e.Handled = True
            End If

            If Me.TextLength = Me.MaxLength Then e.Handled = True 'stop the beep
      End Select
   End Sub
End Class
Comments
Nice Work on the Control

Thank you TnTinMN for your quick response. I appreciate the rework. That was my next goal to make this into a control that could be used whenever it was needed. Nice Work

This article has been dead for over six months. Start a new discussion instead.