locked
Allow only numeric entries in textbox

    Question

  • i have a program which requires for a few numbers to be defined.
    they have to be entered in textboxes.
    when entering any character, which is not a number, the programm crashes.
    how can i avoid that letters can be entered, or how can i check if ony numbers have been entered and no alpha characters?
    thanx!
    Tuesday, January 20, 2009 3:51 PM

Answers

  • Hi,

    This must be the 2nd or the most common question on these forums.

    Try using the SEARCH area at the top of the list of posts first and you will find all these results.>>

    http://http://social.msdn.microsoft.com/Search/en-US/?Refinement=112&query=number+only+textbox+

    Please use SEARCH


    A quick way to search ALL of the VISUAL BASIC.Net forums is to use the search area from here.>>

    http://social.msdn.microsoft.com/Forums/en-US/category/visualbasic/


    Regards,

    John

    For links to VB.Net tutorials see here.>> http://social.msdn.microsoft.com/Forums/en-US/vblanguage/thread/29f2179b-997b-4115-a96d-a0834853b835
    Tuesday, January 20, 2009 4:05 PM
  • I-DotNET said:

    Microsoft could simply add a NumericOnlyTextBox control to .NET and be done with it.

    What is a 'number'? The possibilities are....infinite. So, you have all the tools to create your own. Regardless, there is both a Masked Edit Text Box and an up-down control.

    It is a common request, but the subtleties of the requirement often preclude a generic one size fits all Numbers only text box.



    Stephen J Whiteley
    • Marked as answer by Yichun Feng Friday, January 23, 2009 5:08 AM
    Tuesday, January 20, 2009 6:15 PM
  • > if it were truly that simple, why doesn't one exist?

    Honestly?  Because the IT industry is fundamentally flawed.  If you're curious, here's my rant on Microsoft's certification process:

    http://social.microsoft.com/Forums/en-US/CertGeneral/thread/050114cc-0bfe-4699-b433-51c9113c5e97

    > Regardless, if you feel it's possible, don't you think there's an opportunity there? Go ahead and, as you say, 'simply' create one - 
    > publish it, give us the code for all to use - but you also state 'it's not that simple'. Are you willing to show us how it's done or are 
    > you going to sit on it and blame Microsoft?

    Knock yourself out:

    Imports System.Windows.Forms  
    Imports System.ComponentModel  
    Imports VB6 = Microsoft.VisualBasic  
    Imports CodeLibrary.Text  
     
    ''' -----------------------------------------------------------------------------  
    ''' Class    : NumericTextBox  
    '''   
    ''' -----------------------------------------------------------------------------  
    ''' <summary> 
    ''' This control extends the functionality of a regular Textbox to include a   
    ''' NumericOnly feature.  
    ''' </summary> 
    ''' <remarks> 
    ''' The NumericOnly feature can be turned on or off. When it's on, the user is   
    ''' prevented from entering non-numeric data. Also, the programmer is prevented   
    ''' from setting the Text property to an invalid string. If the user attempts to   
    ''' enter invalid data, the entry will be rejected and a beep will sound. If the   
    ''' programmer tries to set Text to invalid data, it will be rejected and an   
    ''' exception will be raised.   
    '''   
    ''' Numeric data is defined as any digit 0 through 9. There are also properties   
    ''' that will expand that definition to allow a decimal point, a currency (dollar)   
    ''' sign, and a positive sign or negative sign.  
    '''                   
    ''' Although this control can prevent the user from entering non-numeric data,   
    ''' there are situations that it cannot prevent. For example, if AllowPositiveSign   
    ''' is True, the user can type a single keystroke indicating a positive sign but   
    ''' not type anything else. While a positive sign is a valid keystroke, it is not   
    ''' a valid number until a digit is entered. A control cannot force the user to   
    ''' type a number. Also, the user can choose not to enter anything at all. Because   
    ''' of these situations, an IsValidNumber method is provided that will determine   
    ''' whether the contents of the text box is a valid number.  
    ''' </remarks> 
    ''' -----------------------------------------------------------------------------  
    <DesignerCategory("Class"), _  
    ToolboxBitmap(GetType(NumericTextBox), "NumericTextBox")> _  
    Public Class NumericTextBox  
        Inherits CodeLibrary.Windows.Forms.TextBox  
     
        Private Const DEFAULT_ALLOW_CURRENCY_SYMBOL As Boolean = False 
        Private Const DEFAULT_ALLOW_DECIMAL_SEPARATOR As Boolean = False 
        Private Const DEFAULT_ALLOW_NEGATIVE_SIGN As Boolean = False 
        Private Const DEFAULT_ALLOW_POSITIVE_SIGN As Boolean = False 
        Private Const DEFAULT_NUMERIC_ONLY As Boolean = True 
        Private Const DEFAULT_MAX_DECIMAL_PLACES As Integer = -1  
        Private Const DEFAULT_TEXT_ALIGN As HorizontalAlignmentHorizontalAlignment = HorizontalAlignment.Right  
     
    #Region " Private variables "  
     
        ' Private variables  
        Private _currencySymbol As Integer        'ASCII value of currency symbol  
        Private _decimalSeparator As Integer      'ASCII value of decimal Separator  
        Private _negativeSign As Integer          'ASCII value of negative sign  
        Private _positiveSign As Integer '        'ASCII value of positive sign  
        Private _decimalSeparatorString As String 'String value of decimal Separator  
     
        ' Private variables to hold property values  
        Private _numericOnly As Boolean = DEFAULT_NUMERIC_ONLY 
        Private _allowCurrencySymbol As Boolean = DEFAULT_ALLOW_CURRENCY_SYMBOL 
        Private _allowDecimalSeparator As Boolean = DEFAULT_ALLOW_DECIMAL_SEPARATOR 
        Private _allowNegativeSign As Boolean = DEFAULT_ALLOW_NEGATIVE_SIGN 
        Private _allowPositiveSign As Boolean = DEFAULT_ALLOW_POSITIVE_SIGN 
        Private _maxDecimalPlaces As Integer = DEFAULT_MAX_DECIMAL_PLACES 
     
    #End Region  
     
        Public Sub New()  
            MyBase.New()  
            ' Initializes the control with default values.  
            With System.Globalization.CultureInfo.CurrentCulture.NumberFormat  
                _currencySymbol = ToInt32(.CurrencySymbol)  
                _decimalSeparatorString = .CurrencyDecimalSeparator  
                _decimalSeparator = ToInt32(_decimalSeparatorString)  
                _negativeSign = ToInt32(.NegativeSign)  
                _positiveSign = ToInt32(.PositiveSign)  
            End With  
            MyBase.TextAlign = DEFAULT_TEXT_ALIGN 
     
        End Sub  
     
    • Marked as answer by Yichun Feng Friday, January 23, 2009 5:09 AM
    Wednesday, January 21, 2009 2:55 PM
  • Wow... kinda making a mountain out of a mole-hill on this one.

    First, John Oliver is spot-on:  this has been asked and answered so many times that you should be able to find an example of just about every possible way of doing this (and there are many).

    Second, Stephen is also spot-on:  there are two main reasons this control does not exist in the framework already, first being that the devil is in the details and the actual required functionality does affect the design of the control, and the second being that making a numeric textbox is quite simple at the basic level - all you do is tweak the basic model to fit specific needs.

    Here is the basic model for a numeric textbox:

    Public Class NumericTextbox  
        Inherits TextBox  
     
           Protected Overrides Sub OnValidating(ByVal e As System.ComponentModel.CancelEventArgs)  
            MyBase.OnValidating(e)  
            If Not e.Cancel AndAlso TextLength > 0 Then 
                If Not Double.TryParse(Text, Globalization.NumberStyles.Any, Globalization.CultureInfo.CurrentCulture.NumberFormat, NothingThen 
                    e.Cancel = True 
                End If 
            End If 
        End Sub 
     
    End Class 

    That's pretty much all you need to allow any form of a decimal number other than Hex.  And the style can easily be modified to support hex if desired.

    If you want to make that into a "one size mostly fits all" control, then you could expand it into something like this:

    Public Class NumericTextbox  
        Inherits TextBox  
     
        Public Sub New()  
            mAllowedNumberStyles = Globalization.NumberStyles.Any  
            mCultureFormat = Globalization.CultureInfo.CurrentCulture.NumberFormat  
        End Sub 
     
        Private mAllowedNumberStyles As System.Globalization.NumberStyles  
        Public Property AllowedNumberStyles() As System.Globalization.NumberStyles  
            Get 
                Return mAllowedNumberStyles  
            End Get 
            Set(ByVal value As System.Globalization.NumberStyles)  
                mAllowedNumberStyles = value  
            End Set 
        End Property 
     
        Private mCultureFormat As System.Globalization.NumberFormatInfo  
        Public Property CultureFormat() As System.Globalization.NumberFormatInfo  
            Get 
                Return mCultureFormat  
            End Get 
            Set(ByVal value As System.Globalization.NumberFormatInfo)  
                mCultureFormat = value  
            End Set 
        End Property 
     
        Private mNumericValue As Double 
        Public Property NumericValue() As Double 
            Get 
                Return mNumericValue  
            End Get 
            Set(ByVal value As Double)  
                mNumericValue = value  
                Text = mNumericValue.ToString  
            End Set 
        End Property 
     
        Protected Overrides Sub OnValidating(ByVal e As System.ComponentModel.CancelEventArgs)  
            MyBase.OnValidating(e)  
            If Not e.Cancel AndAlso TextLength > 0 Then 
                If Not Double.TryParse(Text, mAllowedNumberStyles, mCultureFormat, mNumericValue) Then 
                    e.Cancel = True 
                End If 
            End If 
        End Sub 
     
    End Class 

    While that control will probably suit 99% of numeric textbox requirements, there could still be a situation where this isn't most appropriate.  So like Stephen said, there isn't really a one-size-fits-all answer to this question.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
    • Marked as answer by Yichun Feng Friday, January 23, 2009 5:09 AM
    Wednesday, January 21, 2009 4:31 PM

All replies

  • Hi,

    This must be the 2nd or the most common question on these forums.

    Try using the SEARCH area at the top of the list of posts first and you will find all these results.>>

    http://http://social.msdn.microsoft.com/Search/en-US/?Refinement=112&query=number+only+textbox+

    Please use SEARCH


    A quick way to search ALL of the VISUAL BASIC.Net forums is to use the search area from here.>>

    http://social.msdn.microsoft.com/Forums/en-US/category/visualbasic/


    Regards,

    John

    For links to VB.Net tutorials see here.>> http://social.msdn.microsoft.com/Forums/en-US/vblanguage/thread/29f2179b-997b-4115-a96d-a0834853b835
    Tuesday, January 20, 2009 4:05 PM
  • Microsoft could simply add a NumericOnlyTextBox control to .NET and be done with it.
    Tuesday, January 20, 2009 5:03 PM
  • I-DotNET said:

    Microsoft could simply add a NumericOnlyTextBox control to .NET and be done with it.

    What is a 'number'? The possibilities are....infinite. So, you have all the tools to create your own. Regardless, there is both a Masked Edit Text Box and an up-down control.

    It is a common request, but the subtleties of the requirement often preclude a generic one size fits all Numbers only text box.



    Stephen J Whiteley
    • Marked as answer by Yichun Feng Friday, January 23, 2009 5:08 AM
    Tuesday, January 20, 2009 6:15 PM
  • bongo 1000 said:

    i have a program which requires for a few numbers to be defined.
    they have to be entered in textboxes.
    when entering any character, which is not a number, the programm crashes.
    how can i avoid that letters can be entered, or how can i check if ony numbers have been entered and no alpha characters?
    thanx!


    try:

     
        Private Sub TextBox1_LostFocus(ByVal sender As ObjectByVal e As System.EventArgs) Handles TextBox1.LostFocus, TextBox1.Enter 
            With TextBox1 
                If .ForeColor = Color.Red Then 
                    MsgBox("Please, enter only a numeric value", MsgBoxStyle.SystemModal) 
                    .Focus() 
                End If 
            End With 
     
        End Sub 
     
        Private Sub TextBox1_TextChanged(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles TextBox1.TextChanged 
            Static LastNumericValue As Double = Nothing 
            With TextBox1 
                If IsNumeric(.Text) Then 
                    .ForeColor = Color.Blue 
                    LastNumericValue = CDbl(.Text) 
                Else 
                    .ForeColor = Color.Red() 
                End If 
            End With 
        End Sub 

    Tuesday, January 20, 2009 6:20 PM
  • Yes and no.  My implementation of a numeric only text box is less than 700 lines of code and it handles things like decimal symbols, hundredths separators, negative signs, plus signs and currency symbols.  Although I've never tested it for internationalization (since I have no need), I did at least try to write it with internationalization in mind.  I guess it doesn't handle non-base 10 numbering systems, so I guess that's a flaw, but most business apps don't need support for non-base 10 numbering schemes. 

    Anyway, I'm of the opinion that application developers really shouldn't be writing general purpose code.  That's the job of library developers which in this case is Microsoft.  A numeric only text box is a very common business need.  There's really no point in having thousands of different developers reinventing the wheel. 

    Tuesday, January 20, 2009 7:58 PM
  • I-DotNET said:

    ...
    Anyway, I'm of the opinion that application developers really shouldn't be writing general purpose code.  That's the job of library developers which in this case is Microsoft.  A numeric only text box is a very common business need.  There's really no point in having thousands of different developers reinventing the wheel. 

    I could not tell enough on how much I agree...

    Tuesday, January 20, 2009 8:08 PM
  • You might want to be careful about using IsNumeric.  It considers "1,,2,3.E4$" to be a valid number.  For most business applications, this would not be valid data.

    (Note my culture setting is "en-us".  I'm not sure what it IsNumeric will do on other cultures or if IsNumeric is even culturally aware since I learned to avoid IsNumeric years ago.)

    EDIT:

    BTW, don't use LostFocus for data validation.  What if the user wants to cancel out of the form?  Using the Validating event instead.

    Also, you should move your code out of the form and into a reusable class.  Either inherit from the TextBox or create an extender control.  Think of a situation where you have an app with dozens of numerica only text boxes.  You wouldn't want to repeat the same bit of code over and over again.
    Tuesday, January 20, 2009 8:28 PM
  • I live in Argentina (spanish-Agentine culture), and I frequently changes the code culture to en-US because is the simplest workaround.
    A textbox should not only being capable of recognize numbers. It should being capable of recognize any value type, as double, boolean or integer.

    Sometime, I used this:

    Public Class Form1 
     
        Private Sub Form1_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load 
            My.Application.ChangeCulture("en-us"
            MyTextBox = New TextBoxOfDouble 
            MyTextBox.Parent = Me 
        End Sub

        Dim WithEvents MyTextBox As TextBoxOfDouble 
        Public Class TextBoxOfDouble 
            Inherits TextBox 
     
            Private Sub TextBox_TextChanged(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Me.TextChanged 
                Try 
                    If Me.Text = CStr(CDbl(Me.Text)) Then 
                        'Is double 
                        Me.ForeColor = Color.Blue 
                    Else 
                        'Is numeric, but not standard representation 
                        Me.ForeColor = Color.Red 
                    End If 
                Catch ex As Exception 
                    Me.ForeColor = Color.Red 
                End Try 
            End Sub 
        End Class 
     
    End Class 

    it also have his problems, although most times it works finely.

    I wish I could write
    Public Class TextBoxOfDouble(of Tipe) 


    but I did not managed to work around
    If Me.Text = CStr(Ctype(Me.Text,Tipe)) Then 'Does not works 

    Tuesday, January 20, 2009 8:48 PM
  • Hi,

    Okay here is code for TextBox1

    But it allows more than one decimal point.

    I have seen code on these forums that only allows one decimal point ( as it should be ).


    Regards,

    John



    Option Strict On 
     
    Public Class Form1  
     
        Private Sub TextBox1_KeyPress(ByVal sender As ObjectByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress  
     
            Select Case e.KeyChar  
                Case ChrW(Keys.D0) To ChrW(Keys.D9)  
                    e.Handled = False 
                Case ChrW(Keys.Back)  
                    e.Handled = False 
                Case "."c  
                    e.Handled = False 
                Case Else 
                    e.Handled = True 
            End Select 
     
        End Sub 
    End Class 
     


    For links to VB.Net tutorials see here.>> http://social.msdn.microsoft.com/Forums/en-US/vblanguage/thread/29f2179b-997b-4115-a96d-a0834853b835
    Wednesday, January 21, 2009 5:25 AM
  • John:

    Unfortunately, it's not that simple.  Among other things, users can completely bypass your data validation code by copying and pasting text into the keypad.  Also, see my previous comment about how this is not reusable.  As a point of comparison, my implementation of a decent numeric only text box is almost 700 lines of code. 

    SJWhiteley: 

    Do you see what I mean now?  I remember having similar lengthy discussions about how to create a good numeric text box 10(!) years ago.  The same issues that came up then are coming up now.  If Microsoft could have simply added a NumericOnlyTextBox to .NET, we'd be done with it. 



    Wednesday, January 21, 2009 1:57 PM
  • I-DotNET said:

    ...

    SJWhiteley: 

    Do you see what I mean now?  I remember having similar lengthy discussions about how to create a good numeric text box 10(!) years ago.  The same issues that came up then are coming up now.  If Microsoft could have simply added a NumericOnlyTextBox to .NET, we'd be done with it. 




    Basically, you have argued my point: if it were truly that simple, why doesn't one exist? The complexities of numeric entry (as demonstrated here) aren't that simple. I can't see how it's Microsofts job to bend to the whim of every 'call to arms': the man-power is a finite resource; there are probably a million questions asking why Microsoft doesn't provide an XYZ widget.

    Regardless, if you feel it's possible, don't you think there's an opportunity there? Go ahead and, as you say, 'simply' create one - publish it, give us the code for all to use - but you also state 'it's not that simple'. Are you willing to show us how it's done or are you going to sit on it and blame Microsoft?

    Stephen J Whiteley
    Wednesday, January 21, 2009 2:19 PM
  • > if it were truly that simple, why doesn't one exist?

    Honestly?  Because the IT industry is fundamentally flawed.  If you're curious, here's my rant on Microsoft's certification process:

    http://social.microsoft.com/Forums/en-US/CertGeneral/thread/050114cc-0bfe-4699-b433-51c9113c5e97

    > Regardless, if you feel it's possible, don't you think there's an opportunity there? Go ahead and, as you say, 'simply' create one - 
    > publish it, give us the code for all to use - but you also state 'it's not that simple'. Are you willing to show us how it's done or are 
    > you going to sit on it and blame Microsoft?

    Knock yourself out:

    Imports System.Windows.Forms  
    Imports System.ComponentModel  
    Imports VB6 = Microsoft.VisualBasic  
    Imports CodeLibrary.Text  
     
    ''' -----------------------------------------------------------------------------  
    ''' Class    : NumericTextBox  
    '''   
    ''' -----------------------------------------------------------------------------  
    ''' <summary> 
    ''' This control extends the functionality of a regular Textbox to include a   
    ''' NumericOnly feature.  
    ''' </summary> 
    ''' <remarks> 
    ''' The NumericOnly feature can be turned on or off. When it's on, the user is   
    ''' prevented from entering non-numeric data. Also, the programmer is prevented   
    ''' from setting the Text property to an invalid string. If the user attempts to   
    ''' enter invalid data, the entry will be rejected and a beep will sound. If the   
    ''' programmer tries to set Text to invalid data, it will be rejected and an   
    ''' exception will be raised.   
    '''   
    ''' Numeric data is defined as any digit 0 through 9. There are also properties   
    ''' that will expand that definition to allow a decimal point, a currency (dollar)   
    ''' sign, and a positive sign or negative sign.  
    '''                   
    ''' Although this control can prevent the user from entering non-numeric data,   
    ''' there are situations that it cannot prevent. For example, if AllowPositiveSign   
    ''' is True, the user can type a single keystroke indicating a positive sign but   
    ''' not type anything else. While a positive sign is a valid keystroke, it is not   
    ''' a valid number until a digit is entered. A control cannot force the user to   
    ''' type a number. Also, the user can choose not to enter anything at all. Because   
    ''' of these situations, an IsValidNumber method is provided that will determine   
    ''' whether the contents of the text box is a valid number.  
    ''' </remarks> 
    ''' -----------------------------------------------------------------------------  
    <DesignerCategory("Class"), _  
    ToolboxBitmap(GetType(NumericTextBox), "NumericTextBox")> _  
    Public Class NumericTextBox  
        Inherits CodeLibrary.Windows.Forms.TextBox  
     
        Private Const DEFAULT_ALLOW_CURRENCY_SYMBOL As Boolean = False 
        Private Const DEFAULT_ALLOW_DECIMAL_SEPARATOR As Boolean = False 
        Private Const DEFAULT_ALLOW_NEGATIVE_SIGN As Boolean = False 
        Private Const DEFAULT_ALLOW_POSITIVE_SIGN As Boolean = False 
        Private Const DEFAULT_NUMERIC_ONLY As Boolean = True 
        Private Const DEFAULT_MAX_DECIMAL_PLACES As Integer = -1  
        Private Const DEFAULT_TEXT_ALIGN As HorizontalAlignmentHorizontalAlignment = HorizontalAlignment.Right  
     
    #Region " Private variables "  
     
        ' Private variables  
        Private _currencySymbol As Integer        'ASCII value of currency symbol  
        Private _decimalSeparator As Integer      'ASCII value of decimal Separator  
        Private _negativeSign As Integer          'ASCII value of negative sign  
        Private _positiveSign As Integer '        'ASCII value of positive sign  
        Private _decimalSeparatorString As String 'String value of decimal Separator  
     
        ' Private variables to hold property values  
        Private _numericOnly As Boolean = DEFAULT_NUMERIC_ONLY 
        Private _allowCurrencySymbol As Boolean = DEFAULT_ALLOW_CURRENCY_SYMBOL 
        Private _allowDecimalSeparator As Boolean = DEFAULT_ALLOW_DECIMAL_SEPARATOR 
        Private _allowNegativeSign As Boolean = DEFAULT_ALLOW_NEGATIVE_SIGN 
        Private _allowPositiveSign As Boolean = DEFAULT_ALLOW_POSITIVE_SIGN 
        Private _maxDecimalPlaces As Integer = DEFAULT_MAX_DECIMAL_PLACES 
     
    #End Region  
     
        Public Sub New()  
            MyBase.New()  
            ' Initializes the control with default values.  
            With System.Globalization.CultureInfo.CurrentCulture.NumberFormat  
                _currencySymbol = ToInt32(.CurrencySymbol)  
                _decimalSeparatorString = .CurrencyDecimalSeparator  
                _decimalSeparator = ToInt32(_decimalSeparatorString)  
                _negativeSign = ToInt32(.NegativeSign)  
                _positiveSign = ToInt32(.PositiveSign)  
            End With  
            MyBase.TextAlign = DEFAULT_TEXT_ALIGN 
     
        End Sub  
     
    • Marked as answer by Yichun Feng Friday, January 23, 2009 5:09 AM
    Wednesday, January 21, 2009 2:55 PM
  • Apparently, posts are limited to 60,000 characters so I have to break it up.

    Part II:

    #Region " Public properties "  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' Determines whether only numeric data is allowed.  
        ''' </summary> 
        ''' -----------------------------------------------------------------------------  
        < _ 
        Category(DESIGNER_CATEGORY), _  
        DefaultValue(DEFAULT_NUMERIC_ONLY), _  
        Description("Determines whether only numeric data is allowed.") _  
        > _  
        Public Property NumericOnly() As Boolean  
            Get  
                Return _numericOnly  
            End Get  
            Set(ByVal value As Boolean)  
                'If this property is set after Text is set, it's possible that  
                'Text is no longer valid. This code makes sure Text is still  
                'valid.  
                If Not Value AndAlso _numericOnly <> Value Then  
                    _numericOnly = Value 
                    If Not IsValid(MyBase.Text) Then  
                        MyBase.Text = String.Empty  
                    End If  
                Else  
                    _numericOnly = Value 
                End If  
            End Set  
        End Property  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' Sets whether the currency sign is allowed when NumericOnly is True. This   
        ''' property has no effect when NumericOnly is False.  
        ''' </summary> 
        ''' -----------------------------------------------------------------------------  
        < _ 
        Category(DESIGNER_CATEGORY), _  
        DefaultValue(DEFAULT_ALLOW_CURRENCY_SYMBOL), _  
        Description("Determines whether a currency sign is allowed when " + _  
        "NumericOnly is True.") _  
        > _  
        Public Property AllowCurrencySymbol() As Boolean  
            Get  
                Return _allowCurrencySymbol  
            End Get  
            Set(ByVal value As Boolean)  
     
                'If this property is set after Text is set, it's possible that  
                'Text is no longer valid. This code makes sure Text is still  
                'valid.  
                If Not Value AndAlso _allowCurrencySymbol <> Value Then  
                    _allowCurrencySymbol = Value 
                    If Not IsValid(MyBase.Text) Then  
                        'remove invalid character  
                        MyBaseMyBase.Text = MyBase.Text.Replace(Convert.ToChar(_currencySymbol), String.Empty)  
                    End If  
                Else  
                    _allowCurrencySymbol = Value 
                End If  
     
            End Set  
        End Property  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' Sets whether a decimal Separator is allowed when NumericOnly is True. This   
        ''' property has no effect when NumericOnly is False.  
        ''' </summary> 
        ''' -----------------------------------------------------------------------------  
        < _ 
        Category(DESIGNER_CATEGORY), _  
        DefaultValue(DEFAULT_ALLOW_DECIMAL_SEPARATOR), _  
        Description("Determines whether a decimal separator is allowed when " + _  
        "NumericOnly is True.") _  
        > _  
        Public Property AllowDecimalSeparator() As Boolean  
            Get  
                Return _allowDecimalSeparator  
            End Get  
            Set(ByVal value As Boolean)  
                'If this property is set after Text is set, it's possible that  
                'Text is no longer valid. This code makes sure Text is still  
                'valid.  
                If value = False AndAlso _allowDecimalSeparator <> value Then  
                    _allowDecimalSeparator = value 
                    If Not IsValid(MyBase.Text) Then  
                        'remove invalid data  
                        MyBaseMyBase.Text = MyBase.Text.Substring(0, MyBase.Text.IndexOf(_decimalSeparatorString))  
                    End If  
                Else  
                    _allowDecimalSeparator = value 
                End If  
            End Set  
        End Property  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' Sets whether a negative sign is allowed when NumericOnly is True. This   
        ''' property has no effect when NumericOnly is False.  
        ''' </summary> 
        ''' -----------------------------------------------------------------------------  
        < _ 
        Category(DESIGNER_CATEGORY), _  
        DefaultValue(DEFAULT_ALLOW_NEGATIVE_SIGN), _  
        Description("Determines whether a negative sign is allowed when " + _  
        "NumericOnly is True.") _  
        > _  
        Public Property AllowNegativeSign() As Boolean  
            Get  
                Return _allowNegativeSign  
            End Get  
            Set(ByVal value As Boolean)  
                'If this property is set after Text is set, it's possible that  
                'Text is no longer valid. This code makes sure Text is still  
                'valid.  
                If Not Value AndAlso _allowNegativeSign <> Value Then  
                    _allowNegativeSign = Value 
                    If Not IsValid(MyBase.Text) Then  
                        'remove invalid character  
                        MyBaseMyBase.Text = MyBase.Text.Replace(Convert.ToChar(_negativeSign), String.Empty)  
                    End If  
                Else  
                    _allowNegativeSign = Value 
                End If  
            End Set  
        End Property  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' Sets whether a positive sign is allowed when NumericOnly is True. This   
        ''' property has no effect when NumericOnly is False.  
        ''' </summary> 
        ''' <value></value>  
        ''' -----------------------------------------------------------------------------  
        < _ 
        Category(DESIGNER_CATEGORY), _  
        DefaultValue(DEFAULT_ALLOW_POSITIVE_SIGN), _  
        Description("Determines whether a positive sign is allowed when " + _  
        "NumericOnly is True.") _  
        > _  
        Public Property AllowPositiveSign() As Boolean  
            Get  
                Return _allowPositiveSign  
            End Get  
            Set(ByVal value As Boolean)  
                'If this property is set after Text is set, it's possible that  
                'Text is no longer valid. This code makes sure Text is still  
                'valid.  
                If Not Value AndAlso _allowPositiveSign <> Value Then  
                    _allowPositiveSign = Value 
                    If Not IsValid(MyBase.Text) Then  
                        'remove invalid character  
                        MyBaseMyBase.Text = MyBase.Text.Replace(Convert.ToChar(_positiveSign), String.Empty)  
                    End If  
                Else  
                    _allowPositiveSign = Value 
                End If  
            End Set  
        End Property  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' Limits the number of digits to the right of the decimal Separator.  -1   
        ''' indicates there is no limit. This property has no effect when either   
        ''' NumericOnly or AllowDecimalSeparator is False.  
        ''' </summary> 
        ''' -----------------------------------------------------------------------------  
        < _ 
        Category(DESIGNER_CATEGORY), _  
        DefaultValue(DEFAULT_MAX_DECIMAL_PLACES), _  
        Description("Limits the number of digits allowed after the decimal separator when " + _  
        "NumericOnly and AllowDecimalSeparator are True.") _  
        > _  
        Public Property MaxDecimalPlaces() As Integer  
            Get  
                Return _maxDecimalPlaces  
            End Get  
     
            Set(ByVal value As Integer)  
                'If this property is set after Text is set, it's possible that  
                'Text is no longer valid. This code makes sure Text is still  
                'valid.  
                If _maxDecimalPlaces <> Value Then  
                    _maxDecimalPlaces = Value 
     
                    If Not ValidateMaxDecimalPlaces(MyBase.Text) Then  
     
                        Dim intDecimalPosition As Integer       'position of the decimal Separator  
     
                        'find position of the decimal Separator  
                        intDecimalPosition = Text.IndexOf(_decimalSeparatorString)  
     
                        'remove invalid character(s)  
                        MyBaseMyBase.Text = MyBase.Text.Substring(0, intDecimalPosition + _maxDecimalPlaces + 1)  
     
                    End If  
                Else  
                    _maxDecimalPlaces = Value 
                End If  
            End Set  
        End Property  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' The text contained in the control.  
        ''' </summary> 
        ''' -----------------------------------------------------------------------------  
        < _ 
        Category(DESIGNER_CATEGORY), _  
        DefaultValue(""), _  
        Description("The text contained in the control.") _  
        > _  
        Public Overrides Property Text() As String  
            Get  
                Return MyBase.Text  
            End Get  
            Set(ByVal value As String)  
                If Not Value Is Nothing Then  
                    If Not IsValid(Value) Then  
                        If Not Me.DesignMode Then  
                            Throw New ArgumentException("Text value is invalid.")  
                        Else  
                            MyBase.Text = Value 
                        End If  
                    End If  
                Else  
                    MyBase.Text = String.Empty  
                End If  
     
            End Set  
        End Property  
     
    #End Region 
    Wednesday, January 21, 2009 2:56 PM
  • Part III

    #Region " Public methods "  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' Determines if Text is a valid number taking into account the values for   
        ''' NumericOnly,  AllowCurrencySign, etc.  
        ''' </summary> 
        ''' <returns>True if Text is a valid number, False if it is not.  
        ''' </returns> 
        ''' <remarks>Because all invalid characters have already been filtered out, there   
        ''' is no need to recheck them here. A simple call to IsNumeric is all that is   
        ''' needed.  
        ''' </remarks> 
        ''' <history> 
        '''     [Jim]   1/27/2004   Created  
        ''' </history> 
        ''' -----------------------------------------------------------------------------  
        Public Function IsValidNumber() As Boolean  
            Return IsNumeric(MyBase.Text)  
        End Function  
     
    #End Region  
     
    #Region " Event handlers "  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' This routine examines the keystroke to make sure it's valid. If it is not   
        ''' valid, the keystroke will be ignored and a beep will sound.  
        ''' </summary> 
        ''' <param name="e"></param> 
        ''' <remarks> 
        ''' </remarks> 
        ''' <history> 
        '''     [Jim]   1/27/2004   Created  
        ''' </history> 
        ''' -----------------------------------------------------------------------------  
        Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)  
     
            If _numericOnly Then  
                Dim blnInvalidChar As Boolean    'flag to indicate the user entered an invalid character  
     
                If Char.IsDigit(e.KeyChar) Then  
                    'make sure decimal places does not exceed max  
                    If _allowDecimalSeparator = True AndAlso _maxDecimalPlaces >= 0 Then  
     
                        'get the portion of text to the left of the keyboard cursor  
                        Dim strStart As String = GetTextLeftOfKeyboardCursor()  
     
                        'get the portion of text to the right of the keyboard cursor  
                        Dim strEnd As String = GetTextRightOfKeyboardCursor()  
     
                        blnInvalidChar = Not ValidateMaxDecimalPlaces(strStart + e.KeyChar + strEnd)  
                    End If  
     
                ElseIf Char.IsControl(e.KeyChar) Then  
                    'nothing to do here  
     
                Else  
                    'get the portion of text to the left of the keyboard cursor  
                    Dim strStart As String = GetTextLeftOfKeyboardCursor()  
     
                    'get the portion of text to the right of the keyboard cursor  
                    Dim strEnd As String = GetTextRightOfKeyboardCursor()  
     
                    blnInvalidChar = Not IsValid(strStart + e.KeyChar + strEnd)  
                End If  
     
                If blnInvalidChar Then  
                    e.Handled = True 
                    VB6.Beep()  
                Else  
                    MyBase.OnKeyPress(e)  
                End If  
     
            End If  
        End Sub  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' This routine traps for when the user pastes text into the text box. If the   
        ''' resulting text is not valid, the paste will be rejected and a beep will   
        ''' sound.  
        ''' </summary> 
        ''' <param name="m"></param> 
        ''' <remarks> 
        ''' </remarks> 
        ''' <history> 
        '''     [Jim]   1/27/2004   Created  
        ''' </history> 
        ''' -----------------------------------------------------------------------------  
        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)  
            Const WM_PASTE As Long = &H302  
     
            If m.Msg = WM_PASTE Then  
                Dim objIData As IDataObject = Clipboard.GetDataObject()  
     
                If objIData.GetDataPresent(DataFormats.Text) Then  
                    Dim strTextToPaste As String = CStr(objIData.GetData(DataFormats.Text))  
     
                    'get the portion of text to the left of the keyboard cursor  
                    Dim strStart As String = GetTextLeftOfKeyboardCursor()  
     
                    'get the portion of text to the right of the keyboard cursor  
                    Dim strEnd As String = GetTextRightOfKeyboardCursor()  
     
                    If IsValid(strStart + strTextToPaste + strEnd) Then  
                        MyBase.WndProc(m)  
                    Else  
                        VB6.Beep()  
                    End If  
     
                End If  
            Else  
                MyBase.WndProc(m)  
            End If  
     
        End Sub  
    #End Region  
     
    #Region " Private routines "  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' This function determines if Text is numeric.  
        ''' </summary> 
        ''' <param name="textToCheck"></param> 
        ''' <returns></returns>  
        ''' <remarks> 
        ''' </remarks> 
        ''' <history> 
        '''     [Jim]   1/27/2004   Created  
        ''' </history> 
        ''' -----------------------------------------------------------------------------  
        Private Shared Function IsNumeric(ByVal textToCheck As String) As Boolean  
            Try  
                Double.Parse(textToCheck)  
                Return True  
            Catch  
                Return False  
            End Try  
        End Function  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' This function determines if Text is a valid string taking into account the   
        ''' values for NumericOnly, AllowCurrencySign, etc.  
        ''' </summary> 
        ''' <param name="Text">The string to validate</param> 
        ''' <returns>True if Text is a valid number, False if it is not.</returns> 
        ''' -----------------------------------------------------------------------------  
        Protected Function IsValid(ByVal text As String) As Boolean  
            Dim intAsciiValue As Integer    'ASCII value of each character in Text  
            Dim blnFoundDecimal As Boolean    'indicates if a valid decimal Separator is found  
            Dim blnFoundPosNegSign As Boolean    'indicates if a valid positive or negative sign has been found  
            Dim blnFoundCurrencySign As Boolean    'indicates if a valid currency sign has been found  
            Dim blnInvalid As Boolean    'indicates if Text contains any invalid data  
     
            If _numericOnly Then  
     
                'examine each character, one at a time to make sure that it's valid  
                For x As Integer = 0 To text.Length - 1  
     
                    'get ASCII value of current character  
                    intAsciiValue = Convert.ToInt32(text.Chars(x))  
                    Select Case intAsciiValue  
     
                        Case Keys.D0 To Keys.D9       'if digit 0 - 9  
                            blnInvalid = False 
     
                        Case _decimalSeparator        'if decimal point  
                            If _allowDecimalSeparator Then  
                                'only allow one decimal point in textbox  
                                If Not blnFoundDecimal Then  
                                    blnInvalid = False 
                                Else  
                                    blnInvalid = True 
                                End If  
                            Else  
                                blnInvalid = True 
                            End If  
                            blnFoundDecimal = True 
     
                        Case _currencySymbol       'if dollar sign  
                            If _allowCurrencySymbol Then  
                                'only allow if it's the first character in textbox  
                                '(not counting positive/negative sign)  
                                If x = 0 Or (blnFoundPosNegSign = True AndAlso x = 1) Then  
                                    blnInvalid = False 
                                Else  
                                    blnInvalid = True 
                                End If  
                            Else  
                                blnInvalid = True 
                            End If  
                            blnFoundCurrencySign = True 
     
                        Case _negativeSign       'if negative sign  
                            If _allowNegativeSign Then  
                                'only allow if it's the first character in textbox  
                                '(not counting dollar sign)  
                                If x = 0 OrElse (blnFoundCurrencySign = True AndAlso x = 1) Then  
                                    blnInvalid = False 
                                Else  
                                    blnInvalid = True 
                                End If  
                            Else  
                                blnInvalid = True 
                            End If  
                            blnFoundPosNegSign = True 
     
                        Case _positiveSign       'if positive sign  
                            If _allowPositiveSign Then  
                                'only allow if it's the first character in textbox  
                                '(not counting dollar sign)  
                                If x = 0 OrElse (blnFoundCurrencySign AndAlso x = 1) Then  
                                    blnInvalid = False 
                                Else  
                                    blnInvalid = True 
                                End If  
                            Else  
                                blnInvalid = True 
                            End If  
                            blnFoundPosNegSign = True 
     
                        Case Else  
                            blnInvalid = True 
                    End Select  
     
                    If blnInvalid Then  
                        Exit For  
                    End If  
     
                Next  
     
                'validate MaxDecimalPlaces  
                If Not blnInvalid AndAlso blnFoundDecimal Then  
                    blnInvalid = Not ValidateMaxDecimalPlaces(text)  
                End If  
            End If  
     
            Return Not blnInvalid  
     
        End Function  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' This function will return True if the number of decimal places in Text are   
        ''' less than or equal to MaxDecimalPlaces.  
        ''' </summary> 
        ''' <param name="Text"></param> 
        ''' <returns></returns>  
        ''' <remarks> 
        ''' </remarks> 
        ''' <history> 
        '''     [Jim]   1/27/2004   Created  
        ''' </history> 
        ''' -----------------------------------------------------------------------------  
        Private Function ValidateMaxDecimalPlaces(ByVal Text As String) As Boolean  
            Dim intDecimalPosition As Integer    'position of the decimal Separator  
     
            'perform check only if needed  
            If _numericOnly = True _  
              AndAlso _allowDecimalSeparator = True _  
              AndAlso _maxDecimalPlaces >= 0 Then  
     
                'find position of the decimal Separator (if it exists)  
                intDecimalPosition = Text.IndexOf(_decimalSeparatorString)  
     
                'if decimal Separator found  
                If intDecimalPosition > -1 Then  
                    'make sure text does not exceed the number of decimal places  
                    If Text.Length - 1 - intDecimalPosition <= _maxDecimalPlaces Then  
                        Return True  
                    End If  
                Else  
                    Return True  
                End If  
            Else  
                Return True  
            End If  
     
        End Function  
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' Returns the portion of text to the left of the keyboard cursor.  
        ''' </summary> 
        ''' <returns></returns>  
        ''' <remarks> 
        ''' </remarks> 
        ''' <history> 
        '''     [Jim]   1/27/2004   Created  
        ''' </history> 
        ''' -----------------------------------------------------------------------------  
        Private Function GetTextLeftOfKeyboardCursor() As String  
            Return MyBase.Text.Substring(0, MyBase.SelectionStart)  
        End Function  
     
     
        ''' -----------------------------------------------------------------------------  
        ''' <summary> 
        ''' Returns the portion of text to the right of the keyboard cursor.  
        ''' </summary> 
        ''' <returns></returns>  
        ''' <remarks> 
        ''' </remarks> 
        ''' <history> 
        '''     [Jim]   1/27/2004   Created  
        ''' </history> 
        ''' -----------------------------------------------------------------------------  
        Private Function GetTextRightOfKeyboardCursor() As String  
            Return MyBase.Text.Substring(MyBase.SelectionStart + MyBase.SelectionLength, _  
                MyBase.Text.Length - (MyBase.SelectionStart + MyBase.SelectionLength))  
        End Function  
     
    #End Region  
     
    End Class 
    Wednesday, January 21, 2009 2:57 PM
  • This was originally written in VB6.  It was upgraded to VB.NET 1.x several years ago.  I'm in the process of upgrading it to .NET 3.5.  It compiles in 3.5 but I need to go through all the "what's new" stuff to see if there are better ways to do things.

    It looks like I have some Hungarian notation that needs to be removed and some (what I consider to be legacy) VB6 calls that I want to change to use native .NET calls, but is should work for most purposes.
    Wednesday, January 21, 2009 3:04 PM
  • Wow... kinda making a mountain out of a mole-hill on this one.

    First, John Oliver is spot-on:  this has been asked and answered so many times that you should be able to find an example of just about every possible way of doing this (and there are many).

    Second, Stephen is also spot-on:  there are two main reasons this control does not exist in the framework already, first being that the devil is in the details and the actual required functionality does affect the design of the control, and the second being that making a numeric textbox is quite simple at the basic level - all you do is tweak the basic model to fit specific needs.

    Here is the basic model for a numeric textbox:

    Public Class NumericTextbox  
        Inherits TextBox  
     
           Protected Overrides Sub OnValidating(ByVal e As System.ComponentModel.CancelEventArgs)  
            MyBase.OnValidating(e)  
            If Not e.Cancel AndAlso TextLength > 0 Then 
                If Not Double.TryParse(Text, Globalization.NumberStyles.Any, Globalization.CultureInfo.CurrentCulture.NumberFormat, NothingThen 
                    e.Cancel = True 
                End If 
            End If 
        End Sub 
     
    End Class 

    That's pretty much all you need to allow any form of a decimal number other than Hex.  And the style can easily be modified to support hex if desired.

    If you want to make that into a "one size mostly fits all" control, then you could expand it into something like this:

    Public Class NumericTextbox  
        Inherits TextBox  
     
        Public Sub New()  
            mAllowedNumberStyles = Globalization.NumberStyles.Any  
            mCultureFormat = Globalization.CultureInfo.CurrentCulture.NumberFormat  
        End Sub 
     
        Private mAllowedNumberStyles As System.Globalization.NumberStyles  
        Public Property AllowedNumberStyles() As System.Globalization.NumberStyles  
            Get 
                Return mAllowedNumberStyles  
            End Get 
            Set(ByVal value As System.Globalization.NumberStyles)  
                mAllowedNumberStyles = value  
            End Set 
        End Property 
     
        Private mCultureFormat As System.Globalization.NumberFormatInfo  
        Public Property CultureFormat() As System.Globalization.NumberFormatInfo  
            Get 
                Return mCultureFormat  
            End Get 
            Set(ByVal value As System.Globalization.NumberFormatInfo)  
                mCultureFormat = value  
            End Set 
        End Property 
     
        Private mNumericValue As Double 
        Public Property NumericValue() As Double 
            Get 
                Return mNumericValue  
            End Get 
            Set(ByVal value As Double)  
                mNumericValue = value  
                Text = mNumericValue.ToString  
            End Set 
        End Property 
     
        Protected Overrides Sub OnValidating(ByVal e As System.ComponentModel.CancelEventArgs)  
            MyBase.OnValidating(e)  
            If Not e.Cancel AndAlso TextLength > 0 Then 
                If Not Double.TryParse(Text, mAllowedNumberStyles, mCultureFormat, mNumericValue) Then 
                    e.Cancel = True 
                End If 
            End If 
        End Sub 
     
    End Class 

    While that control will probably suit 99% of numeric textbox requirements, there could still be a situation where this isn't most appropriate.  So like Stephen said, there isn't really a one-size-fits-all answer to this question.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
    • Marked as answer by Yichun Feng Friday, January 23, 2009 5:09 AM
    Wednesday, January 21, 2009 4:31 PM
  • Hi ALL,

    While on the subject of "one size fits all"

    £1.23

    $4.56

    €7.89

    are in my opinion are not numbers even if you put a plus ( + ) or a minus ( - ) symbol with them.

    They should be confined to a CURRENCY TEXTBOX.

    Some cultures use a comma for a decimal point too, while other cultures use a "period" or full-stop.


    Some cultures use a comma ( or possibly other symbol ) to separate 1000's as in >>

    1,000

    Some cultures allow this separator as well as no-separator as in >>

    1,000,000

    and

    1000000

    The above are just some of the possibilities.

    As for a + or a - on its own then the value could be defaulted to zero.


    Regards,

    John


    For links to VB.Net tutorials see here.>> http://social.msdn.microsoft.com/Forums/en-US/vblanguage/thread/29f2179b-997b-4115-a96d-a0834853b835
    Thursday, January 22, 2009 2:15 AM
  • Like Reed says "KISS" only I check in the change event to give instant feedback to user. you can TryParse any number datatype depending on what you need and only 4 lines of code. I it will even get numbers out of typeO's like $2,3,0.8 is still 230.8

        Private Sub TextBox1_TextChanged(ByVal sender As ObjectByVal e As System.EventArgs) Handles TextBox1.TextChanged  
            Dim ChangedTextBox As TextBox = CType(sender, TextBox)  
            Dim NumberToCheck As Double 
     
            '4 lines to validate number  need Integer then Integer.TryPharse(yada, yada...  
            If Not Double.TryParse(ChangedTextBox.Text, Globalization.NumberStyles.Any, Globalization.CultureInfo.CurrentCulture.NumberFormat, NumberToCheck) Then 
                ChangedTextBox.BackColor = Color.Salmon  
            Else 
                ChangedTextBox.BackColor = SystemColors.Window  
            End If 
     
            Me.Text = NumberToCheck.ToString  
        End Sub 
     
     
    Thursday, January 22, 2009 3:11 AM
  • TechNoHick said:

    Like Reed says "KISS" only I check in the change event to give instant feedback to user. you can TryParse any number datatype depending on what you need and only 4 lines of code. I it will even get numbers out of typeO's like $2,3,0.8 is still 230.8

    I suspect than a really simple solution involves a Regular Expression, but I never had time to learn how to avoid multiple matches.
    Thursday, January 22, 2009 1:22 PM
  • John Anthony Oliver said:

    Hi ALL,

    While on the subject of "one size fits all"

    £1.23

    $4.56

    €7.89

    are in my opinion are not numbers even if you put a plus ( + ) or a minus ( - ) symbol with them.

    They should be confined to a CURRENCY TEXTBOX.

    Some cultures use a comma for a decimal point too other use a "period" or full-stop.

    Some cultures use a comma ( or possibly other symbol ) to separate 1000's as in >>

    1,000

    Some cultures allow this separator as well as no-separator as in >>

    1,000,000

    and

    1000000

    The above are just some of the possibilities.

    As for a + or a - on its own then the value could be defaulted to zero.


    Regards,

    John


    For links to VB.Net tutorials see here.>> http://social.msdn.microsoft.com/Forums/en-US/vblanguage/thread/29f2179b-997b-4115-a96d-a0834853b835



    In my designs, I do have a CurrencyTextBox which inherits from my NumericOnlyTextBox.  As for commas, periods, negative and positive signs, the controls have properties that allows the application developer allow (or disallow) these characters.
    Thursday, January 22, 2009 1:32 PM
  • >  there isn't really a one-size-fits-all answer to this question.

    Hmmm...I wonder how Microsoft managed to get Calc to work?  They seemed to have figured out how to create a good numeric only text box (presumably in C++).  There's no technical reason why the same can't be done in C# or VB.NET.

    In any case, see my code that I already posted.  I created properties that allow developer to customize how the numeric only text box works and if further customization is required, then you simply inherit from it and add whatever customizations you want.

    Developers should NOT be reinventing the wheel.  Not only it is a waste of time, many developers will do it incorrectly (see some of the code already posted to this thread).
    Thursday, January 22, 2009 1:45 PM
  • Hi bongo

    i learnt the following a few years ago

    Dim KeyAscii As Integer = Asc(e.KeyChar)
    Select Case KeyAscii

    'Only allows numbers and back space
    Case Asc("0") To Asc("9"), Asc(ControlChars.Back)
    e.Handled =
    False

    'Only allows carriage return decimal point and hyphen.

    Case Asc(ControlChars.Cr), asc("."), asc("-")
    e.Handled =
    False

    'I used the next control as a focus example
    cboCity.Focus()

    Case
    Else
    e.Handled = True

    End Select

    I still use that now 
    You can add money symbols etc. to this as well


    I hope it helps.

    Zeldacat


    Thursday, January 22, 2009 6:53 PM
  • To I-DotNET:

    You said:  "Hmmm...I wonder how Microsoft managed to get Calc to work?  They seemed to have figured out how to create a good numeric only text box (presumably in C++).  There's no technical reason why the same can't be done in C# or VB.NET."

    The input box for the Calculator does not take symbols such as currency or percentage - so it is less "one size fits all" than using Double.Parse() as shown previously.

    To Guillermo:

    You said:  "I suspect than a really simple solution involves a Regular Expression, but I never had time to learn how to avoid multiple matches."

    Using regular expressions would be much more complex than using Double.Parse.  The Parse() method is by far the simplest solution and providing the appropriate values for NumberStyles will allow you to accept whatever input is appropriate.  And by supplying the current culture info's number format, Parse() will properly handle all of the variations of symbol usage in numbers.

    To TechNoHick:

    You said:  "only I check in the change event to give instant feedback to user"

    This is ok for the color-feedback, however you should still handle the Validating event as well otherwise your code must always first check the backcolor of the textbox before attempting to convert it's text to a usable number.  Also remember that you must check for TextLength = 0 so that the user can change the value, but then erase it and leave it empty.

    To John:

    You mentioned variations in symbols such as currency and separators.

    That is why the "expanded control" example I posted exposes the NumberStyles and NumberFormatInfo to be used by the Parse method as properties on the control.  This allows the user to specify what number styles are accepted (e.g. allow/disallow currency, allow/disallow percentages, allow/disallow Hex characters, etc.), and through the NumberFormatInfo, what decimal and separator symbols will be used.  It also precludes the need to individual numeric and currency textbox controls.

    Also, to reiterate something Stephen mentioned earlier, the framework does include the NumericUpDown and MaskedTextBox controls, each of which can be used to force numeric-only text input.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
    Friday, January 23, 2009 3:40 PM
  •  

    Reed Kimble said:

    To I-DotNET:

    You said:  "Hmmm...I wonder how Microsoft managed to get Calc to work?  They seemed to have figured out how to create a good numeric only text box (presumably in C++).  There's no technical reason why the same can't be done in C# or VB.NET."

    The input box for the Calculator does not take symbols such as currency or percentage - so it is less "one size fits all" than using Double.Parse() as shown previously.


    So, you're saying that Microsoft can figure out how to create a good numeric-only-textbox for decimal, binary, hexidecimal, degrees, radians, etc. but not know how to handle a simple currency or percentage sign?

    Saturday, January 24, 2009 1:43 AM
  • I-DotNET said:

     

    Reed Kimble said:

    To I-DotNET:

    You said:  "Hmmm...I wonder how Microsoft managed to get Calc to work?  They seemed to have figured out how to create a good numeric only text box (presumably in C++).  There's no technical reason why the same can't be done in C# or VB.NET."

    The input box for the Calculator does not take symbols such as currency or percentage - so it is less "one size fits all" than using Double.Parse() as shown previously.


    So, you're saying that Microsoft can figure out how to create a good numeric-only-textbox for decimal, binary, hexidecimal, degrees, radians, etc. but not know how to handle a simple currency or percentage sign?



    Not at all.

    What I'm saying is that a calculator doesn't care what the numbers represent, so symbols such as currency and percent have no meaning to it.  Since they have no meaning they are not accepted as input.

    This is a case-in-point where the desired functionality of the inputbox determines its coding.  Of course they could easily have allowed the inputbox to accept currency or percent symbols, but they chose not to.  That's what I meant by "...less one-size-fits-all than using Double.Parse()...".

     


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
    Monday, January 26, 2009 4:58 PM
  • Interesting thread.
    Bookmarking for my reference.

    And I wholely agree with everything I-DotNET has said in this thread.
    Tuesday, March 10, 2009 10:50 AM
  • I-DotNET,
    I can't see why no one else seems to want to acknowledge your code, but what you've done is really marvellous. Your solution is certainly more comprehensive, all encompassing, and 'one-size-fits-all' than the other snippets of code for the same functionality I've seen in this thread.
    If you don't mind, I'd like the permission to use your custom numeric textbox in my own projects (commercially as well).

    Also, if you ever post an updated version (without any VB6 code), could you please update it here? Maybe the existing posters in this thread won't appreciate it, but I certainly would, and I'm sure many others looking for this solution also would.

    Tuesday, March 10, 2009 1:12 PM
  • reachrishikh said:

    ...Your solution is certainly more comprehensive, all encompassing, and 'one-size-fits-all' than the other snippets of code for the same functionality I've seen in this thread.
    ...



    The control I-DotNET posted might have been OK in VB6, but it is not a strong .Net implementation.

    If you correct the VB6 related errors and try to build this from a paste into VB2008, you will find a number of annoyances with trying to use the control (such as loading a default text value, while specifing numeric only by default, resulting in a text value that will not change in the designer).  There are also the shortcomings noted in the comments by the author, and a lot of individual property management which would be unnecessary of the appropriate .Net objects were utilized.

    Not to take anything away from what I-DotNET posted; like I say, it was probably an OK control in VB6.  But in .Net, expanding upon the basic "Parse() in Validated" design is the way this was intended to be handled.  The little "expanded" example I posted does nearly all of what the VB6 control did (numeric-wise; I don't agree with an IsNumeric property on a 'NumericTextBox' control...).  You could add UI feedback, or options to choose the datatype (Double, Integer, etc.) if you wanted.  The point is that there is no need to test individual characters or do a bunch of string manipulation (all of which is slower than a call to Parse) when utilizing the capabilities of the .Net Framework.

    I would suggest if a reader is in doubt about how to implement a numeric only textbox after reading this thread, that they search these forums for other exiting answers and compare to what's been supplied here.
    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
    Tuesday, March 10, 2009 5:29 PM