# VBForums CodeBank > CodeBank - Visual Basic .NET >  Numeric Text Box

## jmcilhinney

I'm sure that there are numerous examples around that claim to provide a TextBox that accepts numbers only, with varying degrees of completeness and functionality.  I've been intending to do this for some time and it's finally here.  This is a rather rigorous, feature-rich example so it's not for someone who just wants to handle an event and write a couple of lines of code.  It's a custom control, derived from the standard TextBox control, so you would add it to your project as is and then add an instance to your form.  Its features include:

* Text property hidden and data exposed via Value (Decimal) and NullableValue (Decimal?) properties
* Optionally makes a sound when invalid input is rejected
* Optionally accepts a negative sign
* Optionally accepts a decimal point
* Optionally allows blank input
* Optionally converts blank input to zero automatically
* Optionally allows standard or custom numeric format string
* Optionally allows non-default culture formatting rules
* Allows pasting of formatted text.

Potential improvements to be made include:

* Minimum and maximum values
* Display balloon tip when invalid input is rejected
* Customised Toolbox icon

I've attached the class itself and a solution including the class in a DLL and a test application for putting the control through its paces.  I've also included a much simpler class for those with simpler needs.

If you find any issues or can think of any improvements, please post here.  Note that the code was written in VB 2008.  It would need a few adjustments to work in VB 2005; mostly changing If to IIf.  Enjoy!

*I'd also like to encourage anyone who uses the class to post some feedback.*  Did you find using the control simple and intuitive?  Etc.  Many thanks.

----------


## ForumAccount

See attached error, which occurs when adding the control onto the Form. I believe the designer is trying to set the Text property to the Name value (default control behavior).

----------


## jmcilhinney

I guess that occurred when you first added the control to the form, right?  I was testing with a control that I had already added to the form before I changed the code to throw that exception, so I didn't take that scenario into account.  I'll take a look at that.

----------


## jmcilhinney

OK, I've fixed that issue so you can now actually add an instance to a form, which is handy.  :Roll Eyes (Sarcastic):  The new version has replaced the old attached to the first post.

I've hidden the Text property in the designer and so the IDE doesn't try to set it when an instance is created.  That means that I've now shown the Value and NullableValue properties in the designer.  Unfortunately, they don't behave exactly as I'd like.  Once a number is assign to NullableValue there doesn't seem to be a way to null it again.  It can be done in code but not in the designer.  Also, when you change either property you must click into the other one to see it update accordingly.  All seems to be well at run time but I'll try to sort those design time niggles out too.

----------


## NickThissen

> Also, when you change either property you must click into the other one to see it update accordingly.  All seems to be well at run time but I'll try to sort those design time niggles out too.


It seems you can use the RefreshProperties attribute for this, which came up in a post a while ago. See this, especially post #5:
http://www.vbforums.com/showthread.php?t=616661

----------


## jmcilhinney

> It seems you can use the RefreshProperties attribute for this, which came up in a post a while ago. See this, especially post #5:
> http://www.vbforums.com/showthread.php?t=616661


Cool, thanks for that.  I haven't actually done much component development so I think I maybe need to just look through the System.ComponentModel namespace and check out every attribute it exists to see what you can do.

That said, I think I'm going to hide the Value property from the designer anyway.  Thinking about it, there doesn't really seem to be a need to see them both at design time.  You can't actually do anything with Value that you can't with NullableValue anyway.

----------


## dee-u

Other systems could be using other symbols for decimal operators and negative signs, you may want to take that into consideration. And, how about pasting a valid currency text eg. $1.00? Would it not be allowed? It also doesn't allow pasting valid formatter no. eg. 1,000.00.

----------


## jmcilhinney

> Other systems could be using other symbols for decimal operators and negative signs, you may want to take that into consideration. And, how about pasting a valid currency text eg. $1.00? Would it not be allowed? It also doesn't allow pasting valid formatter no. eg. 1,000.00.


Certainly those are things to consider.  The problem with allowing currency symbols to be entered is making sure that it's in the correct position to represent a valid value.  Also, some currency formats might require multiple characters, so you'd have to allow them to enter one without any guarantee that they'd enter the rest.  I think probably allowing a valid currency value to be pasted in but then stripping off the currency formatting would be a good idea, but not allowing currency values to be typed in.  I think the same for group separators would be the way to go.  I'll also correct the fact that different decimal separators are not supported.  Thanks for that.

I've recoded things a bit in an effort to get the NullableValue, Value and Text properties to play together a bit better.  I should have that part sorted by tomorrow, my time, so I'll look at the issues you raised after that.

----------


## jmcilhinney

I've taken on board the stuff dee-u said and I've posted a new version of the control.  I'm yet to test it thoroughly so there may yet be issues.  I should be able to do that in the next 24 hours but, in the mean time, if you try it and have issues or have more suggestions, please post here.

Note that I have removed the DisplayAsCurrency property and added a Format property, allowing you to specify any standard or custom format string.  I've also removed the DisplayBlankAsZero property and added a BlankMode property, which can have values Accept, Reject and ConvertToZero.

----------


## jmcilhinney

I'm still testing but I've fixed a few more bugs so I've updated the attachment in the first post.  Once I've finished testing I'll attach the final class in a DLL project along with the test-bed I used, so you can test its behaviour for yourself and also add the control to your Toolbox rather than having to add it to your own project.

----------


## jmcilhinney

I think I've ironed out all the bugs so I've updated the first post.

----------


## dee-u

If it is not too much to ask then perhaps you can also add a button that will pop-out a calculator? =)

----------


## jmcilhinney

> If it is not too much to ask then perhaps you can also add a button that will pop-out a calculator? =)


I'll do that right after I add the espresso machine.  :Wink:

----------


## V_Beginner

Can I use the Format function at design time to only allow numbers to be displayed like this
123.12 allowing only 2 decimal places?

----------


## rfairhur

Thank you for this code.  It obviously took a lot of work and has a lots of coding techniques I will be applying in the future.  I did find some remaining bugs, however, which I have corrected and extended.  The bugs included:

Any format with spaces in it failed the Decimal.TryParse test, despite being valid for the given culture.  I redid the GetNumberStyles Select Case statements to account for two additional NumberStyles: AllowLeadingWhite and AllowTrailingWhite.  These style options are required to use Decimal.TryParse for the following patterns:

NumberNegativePattern: "- n" requires AllowLeadingWhite and "n -" requires AllowTrailingWhite.
PostiveCurrencyPattern: "$ n" requires AllowLeadingWhite and "n $" requires AllowTrailingWhite.
NegativeCurrencyPattern: "$ n" and "-$ n" require AllowLeadingWhite and "n $", "-n $", "n $-" and "n- $" require AllowTrailingWhite.

After fixing the Currency Pattern I copied those routines and renamed them from Currency to Percent to set up all of the Percent Format conversions.  The differences between handling Currency and Percentage text is that the Decimal.TryParse method cannot be used directly on text with a Percent symbol in it.  So I adapted the code suggested in the fourth post of this thread.  If I detect text with a Percent Symbol I strip out the percent symbol, using Decimal.TryParse using the appropriate cultural NumberStyles and then divide that number by 100 to populate the _nullableValue and _value properties.  That code looks like:



```
    Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
        'Remember the old numeric values.
        Dim oldNullableValue = Me._nullableValue
        Dim oldValue = Me._value

        'Set the new numeric values.  The fields are used rather than the properties so that the Text won't be changed again.
        If Me.TextLength = 0 AndAlso _
           (Me.Focused OrElse Me.BlankMode = BlankModes.Accept) Then
            'The control is blank.
            Me._nullableValue = Nothing
            Me._value = Decimal.Zero
        Else
            Dim number As Decimal

            Dim formatProvider As NumberFormatInfo = Me.GetFormatProvider()
            Dim percentSymbol As String = formatProvider.PercentSymbol
            Dim isPercent As Boolean = Text.Contains(percentSymbol)

            If isPercent Then
                'Text must be able to be parsed.
                Dim s As String = Text

                If s.Contains(percentSymbol) Then
                    s = s.Replace(percentSymbol, "")
                End If

                If Decimal.TryParse(s.Trim, _
                                    Me.GetNumberStyles(True, False, True), _
                                    FormatProvider, _
                                    number) Then
                    'good number, convert percent to decimal
                    number = number / 100
                End If
            Else
                'Get the number the text represents or zero if it doesn't represent a number.
                Decimal.TryParse(Me.Text, _
                                 Me.GetNumberStyles(True, True, True), _
                                 Me.FormatProvider, _
                                 number)
            End If
            Me._value = number
            Me._nullableValue = number
        End If

        'Raise the appropriate events in the appropriate order based on the property that was initially set.
        If Me.nullableValueSet Then
            'Setting the NullableValue property prompted the change.
            Me.OnNullableValueChanged(EventArgs.Empty)

            If Me._value <> oldValue Then
                Me.OnValueChanged(EventArgs.Empty)
            End If

            MyBase.OnTextChanged(e)
            Me.nullableValueSet = False
        ElseIf Me.valueSet Then
            'Setting the Value property prompted the change.
            Me.OnValueChanged(EventArgs.Empty)
            Me.OnNullableValueChanged(EventArgs.Empty)
            MyBase.OnTextChanged(e)
            Me.valueSet = False
        Else
            'Setting the Text property prompted the change.
            MyBase.OnTextChanged(e)

            If Not Me._nullableValue.Equals(oldNullableValue) Then
                Me.OnNullableValueChanged(EventArgs.Empty)
            End If

            If Me._value <> oldValue Then
                Me.OnValueChanged(EventArgs.Empty)
            End If
        End If
    End Sub
```

So now I think everything works, except that I would like it handle all of localized properties of the NumberFormatInfor and CurrencyFormatInfo classes. So I would like to to display native digits instead of arabic digits where they differ, handle NaN, Positive and Negative Infinity, and

----------


## jmcilhinney

@rfairhur, thank you for your kind words and contribution.  When I get a chance I will look at incorporating your changes into the original project and providing a new attachment.  It looks like your post got truncated for some reason.  Did you have additional words of wisdom that were not included?

----------


## rfairhur

I am new to this forum and my sign in cause a little glitch.  I forgot to mention that the code using Percent symbols is easily adapted to handle the Per Mille symbol.  You just have to check for the per Mille symbol when you chack for the percent to deteck which you have ans set a divisor variable to 1000 if the text contains the Per Mille symbol or 100 if it contains the Percent symbol.  As long as the user provides a number format string that uses the "" symbol it will work if the code handling percent works.

The last words that cut off from my post were going to mention handling the Positive Symbol and Scientific Notation.

Because this is a NumberBox, and numbers are great for calculations I plan on making it use an Excel Com link to do calculations if the user includes "=" as the first character.  I would need to suspend normal validating if that was included and set it to handle errors resulting from a system without Excel installed or form a non-numeric return value.  The reason I would love this is that I often have had to pull out a calculator to convert from feet to miles or meters before I could type an entry into a form.  That makes my eyes and brain the real interface and not the form.  It would be easier to type "=12457.23/5820" and have the result "2.3593238636363636363636363636364" returned from Excel in the background, then parsed and rounded in the Numebrbox instantly.  Opening the Calculator on my computer and copy/paste the text of the above calculation took me at least 5 times as long as typing the equation.

----------


## rfairhur

It also looks like the forum parser stripped out the parentheses for the two values in the NegativeCurrencyPattern list that do not contain a negative sign.  In the post they look like "$ n" and "n $", but these should have had parentheses around each of them.

----------


## rfairhur

Final thought.  I absolutely need to handle MinimumUserValue and MaximumUserValue range validation and these ranges need to be from any value to any greater value.   So the properties for ConvertToZero, Prevention of Negative Numbers, and requirement for whole numbers could directly conflict with these settings.  The requirement for whole numbers also does not work with numbers displayed as percents or Per Milles, since they are typically supposed to be stored as fractional values between 1 and 0 (the parser automatically does the multiplication when it adds the symbols with the n% format string, which is why I have to do the division going back to a stripped down numeric value.)

I have several thoughts on how to deal with mutually exclusive settings  Perhaps the best solution would be to handle mutually exclusive options in a choice list like your Reject/Accept/ConvertNullToZero.  I'm not sure how everything would be arranged or what would have priority, but here are some ideas.  I could see these mutually exclusive options: UnrestrictedRange/ZeroToAnyPositive/ZeroToPositiveRange/NegativeToPositiveRange/AnyNegativeToZero/NegativeRangeToZero/NegativeToNegativeRange/PositiveToPositiveRange.  The Range options still can result in errors if the actual values for MinimumValue and MaximumValue are reversed, but these range definitions should limit how much you would have to handle the sign of the value entered (Zero, Positive, or Negative Signed Values are known or can be ignored in all cases before the user Min/Max value pair and cannot be reversed for all but the last two options).  Also for any Value Conflicting With Range Changes to: Null, ZeroOrClosest, Minimum, Maximum, Median.  Additionally for user commit events use Reject/Accept/ConvertNullToZeroOrClosest/ConvertNullToMinimum/ConvertNullToMaximum/ConvertNullToMedian.  Currency/Percentage/PerMille are mutually exclusive and probably should restrict the format specifiers allowed.

Anyway, hopefully these will ideas help with integrating ranges and limit errors.  I will be implementing something, but I would appreciate your reaction to this approach with the class properties and event groupings.

----------


## rfairhur

I meant Mean, not Median.  Also, probably a DisregardConflicts option needs to be implement for existing NumberBox values that conflict with a newly set range limit unless the user touches the value (enter, type, paste).  This would probably be the default, since a new Range Option Setting during runtime may only create a temprorary conflict with the entered values until the Minimum or Maximum range values are fully adjusted.  However, an event could still be raised so that in cases where immediate action is wanted a programmer could respond by performing value validations programmatically from outside of the NumberBox.

----------


## jmcilhinney

> I meant Mean, not Median.  Also, probably a DisregardConflicts option needs to be implement for existing NumberBox values that conflict with a newly set range limit unless the user touches the value (enter, type, paste).  This would probably be the default, since a new Range Option Setting during runtime may only create a temprorary conflict with the entered values until the Minimum or Maximum range values are fully adjusted.  However, an event could still be raised so that in cases where immediate action is wanted a programmer could respond by performing value validations programmatically from outside of the NumberBox.


I would tend to handle that scenario in the same manner as it's done for a NumericUpDown or DateTimePicker.  I don't actually know off the top of my head how that is but I think that it's appropriate that it be consistent.

----------


## rfairhur

When I find something I like I always try pushing a concept to its absolute limits to determine how far an approach can take me.  The Percent behavior gives me the idea that this component could act as a unit converter and presenter for standard units of measure across cultures.

Perhaps using this as some kind of base class, I would like to determine the typical standard units of measure and their associated standard display presentation formats in each culture.  Then I could extends the currency/percent/permille choice list to include other standard unit types (distance, area, volume, speed, weight, etc.) and then set a property establishing the related base unit standard (meters, square meters, cubic meters, liters, kilometers/hour, kilos, etc.).  The display would be in the culturally accepted format.  A conversion factor operation to other standard units (U.S. feet, square feet, cubic feet, gallons, miles/hour, U.S. pounds, etc.) could also be exposed.  Most likely, the component would always take inputs and do the presentations in the cultural standard units, but output converted units through two new properties called something like ConversionUnits and ConvertedValue that would output a converted decimal number to the specified alternative unit of measure (hopefully with some kind of way of indicating its maximum precision given the other unit settings).  Alternatively, the display might show the converted units, but take numeric entries and store the core numeric values in culturally standard units.

I work with engineers and with GIS, and units of measure and conversions are an every day part of my work.  This accounts for why I need range constraints in my validations, because real world roads do not have infinite distances of offset from a given intersection and those offsets are not always reported in one distance unit standard.  Since I am in the U.S. and normally use non-metric U.S. measurements, I have to use a calculator to do such conversions even within a given unit type. (i.e., for distance it is not a simple movement of a decimal point to go from feet to inches, feet to yards, or feet to miles).

Anyway, do you think I have already reached the breaking point with this class, or do you think this is a reasonable extension of its input and presentation behaviors?  I realize this is normally done at the form level, but I feel I am more likely to introduce a conversion bug passing values within a form that is being constantly remade and tweaked than I would be in a well defined class that is closest to the actual values being inputted or outputted and that has some way of storing and reporting its precision specifications.

----------


## rfairhur

I forgot about another key bug in your component when I wrote my first post.  Whenever you use an OrElse set of tests that parse the input text to a number, you have to send separate instances of the text value through each of the tests, not the originally passed text variable itself.  Your code as writen tests the actual text variable.  What happens is that if any succesive test in the series fails, the text value and number are changed to "" and 0 and those are the values used for any subsequent test.  This results in the _nullableValue and _value properties being set to 0 even if it was non-zero at first and would have passed the OrElse condition at a later test in the series.  

I rewrote these OrElse parsing tests to use a separate text variable that held a copy of the passed text value for each test in the block to determine the boolean value of the full series of OrElse conditions.  I did not use any of the returned parsed test text variable outputs in the code that followed even if the tests returned true.  Instead all later code applied to the originally passed unaltered text variable.  This ensured that when the proper parsing occurred the originally passed text value would be parsed and retained in the _nullableValue and _value properties.

----------


## rfairhur

> I would tend to handle that scenario in the same manner as it's done for a NumericUpDown or DateTimePicker.  I don't actually know off the top of my head how that is but I think that it's appropriate that it be consistent.


I agree with you that I need to follow the best known conventions for range values.  The NumericUpDown component seems to be closest to this component, since it also handles numeric values.  I have tested the NumericUpDown component and found that its behavior can be descrined in three scenarios when a user value is set.  The ideal situation is where the new value being set for the minimum or the maximum parameter do not conflict with each other and the value seen by the user fits within in the new range.  In this case only the one internal property of the component that received a new set value is changed.  This should be the normal practice where possible.

The next most likely situation occurs where the new property setting for the minimum or maximum does not cause these two internal component properties to be improperly ordered, but the new range setting will not include the value currently seen by the user.  In this case the minimum and maximum properties do not affect each other; however, when the value seen by the user was below the new minimum setting it is reset to match the new minimum value when the minimum property is set.  Alternatively, if the value seen by the user was above the new maximum it is reset to match the new maximum value when the maximum property is set.  If the user value is Null it is left Null.

The final scenario occurs when the new the minimum and maximum value setting would cause these two values to be improperly ordered relative to each other (i.e. the program sets the minimum value above the current maximum or the program sets the maximum below the current minimum) then all values (minimum, maximum, and the value seen by the user) are all simultaneously set by the property change to the newest property value (since that is the only acceptable value now allowed in the range).  so if both new range values are below the current minimum value the user's value will always match the new maximum.  Alternatively, if the two new range values exceed the current maximum, the user's value will always match the new minimum of the range.  If the user value is Null it is left Null.

There is no gauruntee that zero will be included in the range, so I would adjust the ConvertToZero option to account for the range adjustment process.  If Null is not allowed and Null is not rejected then I would describe the final option as SetToZeroAdjustedForRange.  However, the NumericUpDown does not do this.  Instead, it seems to keep track of the last values that it was set to and moves from Null to the value closest to that last value when the spinner is hit.  If it never had a value it favors the maximum value (at least I think it does, unless there is some sort of persistence across runs I am not aware of).  So I would name this behavior as SetToLastValueAdjustedForRange.  Anyway, I would also add SetToMaximum and SetToMinimum for occassions where Zero or some unknown last value is not nearest to the default Range value desired in the place of Null.

----------


## rfairhur

I think the NumberBox prevents me from using the decimal separator for the ? (Latin, ?) groups.  The separator is "," but that character gets stripped out when I try to type it or paste it.  So the number round to 0 and then truncate to 0 with these cultural settings.  However, I thought I had this working in my version at work (I restarted the code fixes at home since I cannot access my work version and I did not send it to my home computer).  So I think there may be another bug fix required that is related to the separators (which at the moment I cannot remember what I did to fix it).  Anyway, trace out moving between Tamazight (Latin, Algeria) and Uzbek (Latin, Uzbekistan) and any other cultural setting to see if you spot an error with separator parsing.

Update:

I have found that the failure with Tamazight (Latin, Algeria) is that it will not parse the currency format no matter what I do.  It always returns 0 when it fails the Decimal.TryParse method, even though all of the NumberStyle settings appear to be set correctly.  Since the decimal and thousand separators reverse when outputted to currency using the ToString method, perhaps this failure is due to this language being a right to left language and my computer is not set up for that.  So probably only a person using that cultural setting natively could really test if the NumberBox is working.  If not there must either be a secret NumberStyle component, or Microsoft has a bug in that culture (quite possible).

As far as the Uzbek (Latin, Uzbekistan) setting, apparently their currency is not worth reporting with a decimal point, because the formatting to their currency always rounds to a whole number.  As long as I use whole numbers that setting is not giving me problems.  I also do not seem to have problems with the other ? (Latin, ?) settings, so I think these are just unique cases.

So here is my revised GetNumberStyles code that correctly sets up the cultural based TryParse for all formats except for the Tamazight (Latin, Algeria).  This code excludes the enhanced logic that deals with the Percent numberSytle flags (but that code essentially uses the settings of the CurrencyNegativePatterns that are not enclosed in parentheses with adjusted index values that match the msdn website for the PercentNegativePatterns and the number 3 index style included in the PercentPositivePatterns.):



```
    Private Function GetNumberStyles(ByVal allowFormatting As Boolean, ByVal allowCurrency As Boolean) As NumberStyles
        Dim styles As NumberStyles = NumberStyles.None

        If allowFormatting Then
            styles = styles Or NumberStyles.AllowThousands
        End If

        If allowCurrency Then
            styles = styles Or NumberStyles.AllowCurrencySymbol
            Select Case Me.GetFormatProvider().CurrencyPositivePattern
                Case 2 '$ n
                    styles = styles Or NumberStyles.AllowLeadingWhite
                Case 3 'n $
                    styles = styles Or NumberStyles.AllowTrailingWhite
            End Select
        End If

        If Me.AllowNegative Then
            'A leading negative sign is always permitted.
            styles = styles Or NumberStyles.AllowLeadingSign

            If allowCurrency Then
                'Allow parentheses or a trailing negative sign only if the current currency pattern allows it.
                Select Case Me.GetFormatProvider().CurrencyNegativePattern
                    Case 0, 4 '($n), (n$)
                        styles = styles Or NumberStyles.AllowParentheses
                    Case 3, 6, 7 '$n-, n-$, n$-
                        styles = styles Or NumberStyles.AllowTrailingSign
                    Case 8 '-n $
                        styles = styles Or NumberStyles.AllowTrailingWhite
                    Case 9 '-$ n
                        styles = styles Or NumberStyles.AllowLeadingWhite
                    Case 10, 13 'n $-, n- $
                        styles = styles Or NumberStyles.AllowTrailingSign
                        styles = styles Or NumberStyles.AllowTrailingWhite
                    Case 11 '$ n-
                        styles = styles Or NumberStyles.AllowTrailingSign
                        styles = styles Or NumberStyles.AllowLeadingWhite
                    Case 12 '$ -n
                        styles = styles Or NumberStyles.AllowLeadingWhite
                    Case 14 '($ n)
                        styles = styles Or NumberStyles.AllowParentheses
                        styles = styles Or NumberStyles.AllowLeadingWhite
                    Case 15 '(n $)
                        styles = styles Or NumberStyles.AllowParentheses
                        styles = styles Or NumberStyles.AllowTrailingWhite
                End Select
            Else
                'Allow parentheses or a trailing negative sign only if the current number pattern allows it.
                Select Case Me.GetFormatProvider().NumberNegativePattern
                    Case 0 '(n)
                        styles = styles Or NumberStyles.AllowParentheses
                    Case 2 '- n
                        styles = styles Or NumberStyles.AllowTrailingSign
                        styles = styles Or NumberStyles.AllowLeadingWhite
                    Case 3 'n-
                        styles = styles Or NumberStyles.AllowTrailingSign
                    Case 4 'n -
                        styles = styles Or NumberStyles.AllowTrailingSign
                        styles = styles Or NumberStyles.AllowTrailingWhite
                End Select
            End If
        End If

        If Me.AllowDecimal Then
            styles = styles Or NumberStyles.AllowDecimalPoint
        End If

        Return styles
    End Function
```

----------


## rfairhur

Duplicate post deleted

----------


## rfairhur

Just one other thought.  You can make the text box itself into a calculator using a text parser and equation evaluator like this one located on the codeproject website..  I think that by suspending your parsing routines whenever the user begins a string with an "=" sign you could switch to the evaluator.  When you trigger the evaluator you would need to strip the "=" sign off before passing it to the evaluator.  This is much faster than interop with Excel (I tried that) and does not require the end user to have any software installed.  I know how to extend the evaluator to do functions that accept nearly unlimited parameters through a quoted delimited input string.  It can do all standard arithmetic and all of the core math equations.  The evaluator reports its return type, so detecting if you have a double value is easy.  Because it allows for object dot operator evaluations, you have to be careful to preceed decimals with a leading zero.  I can probably disable that components, since average users won't need that.

Beyond the built in arithmatic, comparison, and base type parsing class methods and the pi constant, using these classes here is the list of functions I have working at runtime that a user can directly input within a textbox to get an evaluated result:

*Functions With A Pedefined Set Of Parameters*

Type Manipulation Functions

Numeric Casting Functions

Dec(Value)
Int(Value)

String Functions

Trim(String)
LeftTrim(String)
RightTrim(String)
PadLeft(String, wantedLength, Optional addedChar)
Index(String, SearchString, Optional delimiter)
Inlist(String, list, Optional delimiter)
Split(String, Optional delimiter)
Chr(cInteger)
ChCR()
ChLF()
ChCRLF()
Lower(String)
Upper(String)
WCase(String)
Replace(BaseString, SearchString, ReplaceString)
Substr(String, From, Optional Length)
Len(String)
Format(Value, style)
Entry(Integer, String, Optional delimiter)

DateTime Functions

Now()
Today()
Date(year, month, day)
Year(DateTime)
Month(DateTime)
Day(DateTime)
WeekDay(DateTime)
Long_date(DateTime)
Format_date(DateTime, Optional format)
Format(Value, style)

Currency Functions

Money(Double)
Format(Value, style)

Conditional Logic Functions

If(Condition, TrueValue, FalseValue)

Database Functions

DbNull()


Mathematical Functions

Math Absolute Value Functions

Abs(Value)

Math Rounding Functions

Ceil(Value)
Floor(Value)
Round(Value)
Round(Value, PrecisionInteger)
Trunc(Value, Optional Precision)

Math Modulus Function

Mod(x, y)

Math Trigonometry Functions

Sin(Value)
Cos(value)
Tan(Value)
Asin(Value)
Acos(value)
Atan(Value)
Atan2(x, y)
Cosh(Value)
Sinh(value)
Tanh(Value)

Math Logarithm Functions

Exp(Base, powerExponent)
Power(Double, PowerExponent)
Sqrt(Double)
Exp(Value)
Log(Value)
Log10(Value)

Math Random Number Functions

Rnd()


*Functions with no predetermined limited on input values:*

Math Summation

Sum(quoted delimited string allowing nearly limitless items)

Math Range Functions

Min(quoted delimited string allowing nearly limitless items)
Max(quoted delimited string allowing nearly limitless items)
Median(quoted delimited string allowing nearly limitless items)
Range(quoted delimited string allowing nearly limitless items)

Math Statistics Functions

Avg(quoted delimited string allowing nearly limitless items)
Count(quoted delimited string allowing nearly limitless items)

Delimited String Sorting

Sort(quoted delimited string allowing nearly limitless items) ' sorted based on fully evaluated types and equation results
SortHalfEval(quoted delimited string allowing nearly limitless items) ' sort based on full evaluation, but returns original strings
SortNoEval(quoted delimited string allowing nearly limitless items) ' Alpha sort without evaluation

So I don't think you have to add the expresso machine first to get an inline calculator.

----------


## rfairhur

I have made the OnTextChanged event not perform rounding based on the Display precision.  This way the full number typed or passed to the NumberBox is preserved, but can still display only the number of significant digits expected by the culture.  This fixes the number invaliation that occurred with the Tamazight (Latin, Algeria) culture and the rounding issues that occurred with the Uzbek (Latin, Uzbekistan) culture.  The number stored is now as precise as the Decimal type is capable of storing.  A new property could be created to specify an internal rounding precision level, but I have not created that property at this time.

Although the code is not posted here, I have added Minimum and Maximum range properties.  Setting these properties affects many of the other properties.  for example, the AllowNegative property had to become a read only property.  It can only be set by changing the Minimum property.  If the Minimum is 0 or greater the AllowNegative property becomes False.  If the Minimum is less than 0 than the AllowNegative property becomes true.  Also, the AllowDecimal property will be reset to True if the Minimum or Maximum values have a floating value (similarly, setting the AllowDecimal to false will round the Minimum and Maximum values, if necessary).  

I also have made two additional properties that determine how the Minimum and Maximum value range will be enforced.  One property controls enforcing the range on the user's input and the other enforces the range when property changes are made programatically.  They have 3 states similar to the AllowBlank property, which are:  Allow, ConvertToNearestRangeEnd, and Reject.  Allow does not enforce the Range limits but will still respect the AllowNegative property setting if it is False (basically what the tool does now).  The Convert setting will automatically change out of range values to Zero or the closest end of a range when the user leaves the numberbox, or when the properties related to the Minimum and/or Maximum create an out of range condition.  Reject prevents a user from leaving a numberbox when a value is out of range.  Currently Reject has little use relative to the setting of properties, but I may change that if I find that accidental property change combinations need to be prohibited until values are corrected manually before allowing the new property setting changes.

This code has been very useful.  I really do appreciate what I can do with this tool for user validation and data displays.  The display also respects all of the Custom format specifiers ("0", "#", "-", ".", "," (both as a separator and a scaler), "%", "‰", "E0", "E+0". "E-0", "e0", "e+0", "e-0", "\", string literals, and the ";" Section Separator.  So I now can display formats like "#,##0' m';-#,##0' m'" without corrupting the underlying number stored.  I am now going to focus on extending the supported number and currency formats the component will correctly display and parse to have dynamic behaviors that respond to new cultural property settings.  I want one base format specified for the Invariant Type (like "#,##0' m';-#,##0' m'") to reconfigure itself to present the number format associated with each specific culture when a new culture is selected (like "#,##0' m';(#,##0)' m'"), just as Standard Number Format Strings like "C", "E", "F", "G", "N", and "P" specifiers do (the "D", "R" and "X" specifiers do not appear to be supported for the Decimal type which the tool uses).  I hope my comments and code revisions prove to be useful for others.



```
    ''' <summary>
    ''' Raises the <see cref="TextChanged" /> event.
    ''' </summary>
    ''' <param name="e">
    ''' The data for the event.
    ''' </param>
    ''' <remarks>
    ''' Sets the <see cref="NullableValue" /> and <see cref="Value" /> properties when the <see cref="Text" /> changes.
    ''' </remarks>
    Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
        'Remember the old numeric values.
        Dim oldNullableValue = Me._nullableValue
        Dim oldValue = Me._value
        Dim number As Decimal
        Dim s As String = Me.Text
        Dim fmtProvider As NumberFormatInfo = Me.GetFormatProvider()
        Dim decimalChar As String = fmtProvider.NumberDecimalSeparator
        Dim negativeSign As String = fmtProvider.NegativeSign
        Dim checkFormat As String = Me.Format
        'Set the new numeric values.  The fields are used rather than the properties so that the Text won't be changed again.
        If Me.TextLength = 0 AndAlso _
           (Me.Focused OrElse Me.BlankMode = BlankModes.Accept) Then
            'The control is blank.
            Me._nullableValue = Nothing
            Me._value = Decimal.Zero
        Else
            Dim percentSymbol As String = fmtProvider.PercentSymbol
            Dim isPercent As Boolean = Text.Contains(percentSymbol)
            Dim perMilleSymbol As String = fmtProvider.PerMilleSymbol
            Dim isPerMille As Boolean = Text.Contains(perMilleSymbol)
            If isPercent Or isPerMille Then
                number = Me._value
            Else
                'Get the number the text represents or zero if it doesn't represent a number.
                Dim sTemp As String = s
                If Not Decimal.TryParse(sTemp, _
                                     Me.GetNumberStyles(True, True, True), _
                                     Me.FormatProvider, _
                                     number) Then
                    number = Me._value
                    s = sTemp
                End If
            End If
            If allowFormattingWhenFocused Then
                If Not Me.NullableValue.HasValue() Then
                    s = ""
                    number = Me._value
                Else
                    s = Me._value.ToString(Me.Format, Me.FormatProvider)
                    number = Me.Value
                End If
            End If
        End If

        'Raise the appropriate events in the appropriate order based on the property that was initially set.
        If Me.nullableValueSet Then
            'Setting the NullableValue property prompted the change.
            Me.OnNullableValueChanged(EventArgs.Empty)
            If Me._nullableValue.HasValue Then
                Me._value = CDec(Me._nullableValue)
            Else
                Me._value = Decimal.Zero
            End If
            If Me._value <> oldValue Then
                Me.OnValueChanged(EventArgs.Empty)
            End If

            MyBase.OnTextChanged(e)
            Me.nullableValueSet = False
        ElseIf Me.valueSet Then
            'Setting the Value property prompted the change.
            Me.OnValueChanged(EventArgs.Empty)
            Me.OnNullableValueChanged(EventArgs.Empty)
            MyBase.OnTextChanged(e)
            Me.valueSet = False
        Else
            Dim pos As Integer = Me.SelectionStart
            If allowFormattingWhenFocused Then
                If Me.Text = Me.GetFormatProvider.NegativeSign OrElse Me.Text = Me.GetFormatProvider.NumberDecimalSeparator OrElse Me.Text = Me.GetFormatProvider.NegativeSign & Me.GetFormatProvider.NumberDecimalSeparator Then
                    Me.Text = ""
                    number = Decimal.Zero
                Else
                    Me.Text = s
                End If
            ElseIf Not Me.Focused Then
                If Me.Text = Me.GetFormatProvider.NegativeSign OrElse Me.Text = Me.GetFormatProvider.NumberDecimalSeparator _
                    OrElse Me.Text = Me.GetFormatProvider.NegativeSign & Me.GetFormatProvider.NumberDecimalSeparator Then
                    Me.Text = ""
                    number = Decimal.Zero
                Else
                    Me.Text = s
                End If
            ElseIf Me.Text <> s Then
                Me.Text = s
            End If
            If s <> Me.Text Then
                Dim testStr As String = s
                Dim testText As String = Me.Text
            End If
            'Setting the Text property prompted the change.
            MyBase.OnTextChanged(e)

            If number <> Me.Value Then
                Me._value = number
                If Me.Text = "" Then
                    Me._nullableValue = Nothing
                Else
                    Me._nullableValue = number
                End If
            ElseIf (Me.Text = "" OrElse Me.Text = GetFormatProvider.NegativeSign OrElse Me.Text = GetFormatProvider.NumberDecimalSeparator _
                OrElse Me.Text = GetFormatProvider.NegativeSign & GetFormatProvider.NumberDecimalSeparator) Then
                Me._value = number
                Me._nullableValue = Nothing
            Else
                Me._value = number
                Me._nullableValue = number
            End If
            If Not Me._nullableValue.Equals(oldNullableValue) Then
                Me.OnNullableValueChanged(EventArgs.Empty)
            End If

            If Me._value <> oldValue Then
                Me.OnValueChanged(EventArgs.Empty)
            End If
        End If
    End Sub
```

----------


## gimomars

This is what I'm looking for. Thumbs up for you Sir!  :Thumb:

----------


## gimomars

Hi Sir, just want to ask how to use the Number Group Separator. It does't changed my value. From 1000 to 1,000.

Regards,

----------


## jmcilhinney

> Hi Sir, just want to ask how to use the Number Group Separator. It does't changed my value. From 1000 to 1,000.
> 
> Regards,


If all you want is for numbers to be displayed with group separators then you would use the original code and set the Format property to a standard or custom numeric format string that included group separators.  The MSDN documentation can tell you what those are.

----------


## priyamtheone

Thanks jmcilhinney for presenting us with the component. It really serves a lot.
However, while working with it I bumped onto a bug that occurs while using the currency format. When you change the Format and Location (English- United States) of your O.S. to something else, the display text of the NumberBox doesn't get updated while building the solution at the design time as well as when the form is loaded. In order to be updated, you need to manually set focus to and loose focus from it.

For an example, try doing the following:
From Control Panel ensure the Format and Location of your O.S. are English (United States) and United States respectively. Now start a new VS.Net project. Drag a new NumberBox and a Button on a form and change the BlankMode and Format properties of the NumberBox to 'ConvertToZero' and 'c' respectively. The display text should be '$0.00'. Now change the Format and Location of the O.S. to English (United Kingdom) and United Kingdom respectively. See, that doesn't change the display text of the NumberBox. Clean the solution and build it; that still doesn't solve the purpose. Now run the application, when the form is loaded you can see the display text is still '$0.00' while it is supposed to be '£0.00'. It is only when you click in the NumberBox and loose focus by clicking on the Button that the display text is updated properly.

To test, I started debugging the NumberBox class by applying breakpoint to check if the format is literally set when the NumberBox is initialized. Surprisingly when the control flow comes to the DisplayNumber method, in the last line, the proper text (£0.00) is actually getting set to the NumberBox. But somehow it's not taking effect later.

I'm not pretty sure but I think there's a problem in the designer class of the form that hosts the NumberBox. Open the designer class (e.g. Form1.designer.vb) and check where the NumberBox is initialized in the InitializeComponent method. There you can see that the text of the NumberBox is set to '$.00' even if we have already changed the format now. I think as the display text was set to '$0.00' when we first created the NumberBox, it is kind of getting glued here. The designer is not updating any subsequent change for some reason.

I'm using this component in my application and it's already through midway. So I can't start it all over. Hence I would request you to kindly look into the matter and provide me with some help.

Regards!

----------


## jmcilhinney

> I'm using this component in my application and it's already through midway. So I can't start it all over. Hence I would request you to kindly look into the matter and provide me with some help.


I'll try to have a look at that over the weekend.

----------


## priyamtheone

Look to hear from you soon.
Thanks!

----------


## Eric P

Hi,
Your control has very nice functionalities.
Did you add MinValue and MaxValue properties to bound the user input on a newer version ?

Best regards,
Eric.

----------


## rfairhur

I am attaching my version of the number box originally posted here.  I have modified my version to take care of some glitches I encountered and expand or alter some of its functionality.

The original number box produced errors for some of the available cultural localization formats.  This version has corrected those errors and been tested for all cultural localization settings predefined by Microsoft.

I believe I have tested the Format parameter for all of the standard numeric formatting codes and the full set of custom format codes, including the percent and per mille codes.  If the Format parameter contains a code like #,##0.00' Miles' the box will display numbers like 2.18903307 as "2.19 Miles" and if the code is #0.##% the box will display numbers like 0.18906307 as 18.91% without any loss of precision to the underlying number.

This version allows a user to set a minimum and maximum value bound, and these bounds control the related flag that only allows positive values.  So if the bounds exclude negative numbers the flag is automatically set to only allow positive numbers, but if the range includes negative numbers the flag is set to allow negative numbers.

The number box provides 3 options for responding to invalid input related to leaving the number box blank, external user inputs of out of range numbers, or internal programmatic inputs of out of range numbers.  The responses include leaving the number unchanged and sending an error event, automatically resetting the value to stay within the nearest bound, or accepting the value so that error handling can be controlled by the custom code applied outside of the number box at the project level.  Paste events into the box get validated according to these rules as well as keyboard inputs.

I have also adapted the techniques outlined in this thread to create a DateTimePicker textbox that ensures that valid dates are entered.  I believe that it combines the best aspects of a date time picker tool and a masked text box without the drawbacks of either of those component types.  Like the Number Box it deals with whether or not blank date values can be displayed.   It allows multiple date display formats that comply with all of the cultural localization settings I was aware of, while storing an underlying standardized date value.  Users are only allowed to type in numbers and separators.  The user can choose to type numbers only and separators will be added by the box according to the local rules for 8 digit dates plus separators.  The tool attempts to make sense of dates as they are being typed and supplies leading zeros even if the user does not type them for month or day components when they are needed.  It also tries to follow rules for conversion of 2 digit years to 4 digit years and lets you define the base century that you want to use for interpreting 2 digit years.  An actual date picker calendar can be displayed by the user for choosing a date if they press the drop down arrow on the right of the box.  There is also an optional setting that can automatically trigger the calendar to be displayed if the user attempts to leave the box after entering an invalid date value.

Once the user leaves the box the underlying date will be stored in the local 8 digit plus separator format, but will be displayed in the box in whatever format is specified in the Format parameter.  Paste events attempt to parse dates of a wider array of formats according to the localization settings, but the preference is to paste locally compliant 8 digit dates with local separators.

The date time picker technically was only tested for Dates, not Dates and Times. Dealing with Time formats would require additional enhancements.  Validating date inputs while a user types is much harder than numeric inputs, so I do expect that there are still some conditions that can trigger a bug, but hopefully those triggers are rare.   I welcome any input on this tool as well.

I hope you find these modifications and enhancements useful.

----------


## jmcilhinney

@rfairhur, your efforts are appreciated.  This control was only ever intended as a proof of concept and I never did get back to it but it sounds like you've extended it into something that could genuinely be used in production code.  I'll check out your modifications when I get a chance.

----------


## rfairhur

Just a couple of other notes about my DateTimePicker.  It uses a Minimum and Maximum value to define a date range.  Like the Number Box, it has 3 response options that can apply separately defined responses for invalid blanks, or out of range dates from user input or from programmatic input. Finally, my control only supports Gregorian calendars like the Microsoft DateTimePicker.

----------


## Eric P

@rfairhur, thank you very much for your post. Yes, it is very useful.

Please find some comments :
- I was wondering if the ErrorProvider could not be defined directly in the NumberBox control
- I would prefer to have a kind of ballon, displaying the Min/Max message as long as the user input is not in the range. This certainly implies to make the validation during the KeyPress event
- I also need to check values with decimal point (from 0.1 to 0.5 for example)
- The decimal separator should be read from Windows
- Find an "easy way" to localize the error messages (avoiding to redefine them for each control on a form).

I did not test the DateTimePicker yet.

I am going to have a look on how to add a Tooltip inside the NumberBox, move the validating process in KeyPress and move the management of the messages also in the control.

Eric.

----------


## rfairhur

> @rfairhur, thank you very much for your post. Yes, it is very useful.
> 
> Please find some comments :
> - I was wondering if the ErrorProvider could not be defined directly in the NumberBox control
> - I would prefer to have a kind of ballon, displaying the Min/Max message as long as the user input is not in the range. This certainly implies to make the validation during the KeyPress event
> - I also need to check values with decimal point (from 0.1 to 0.5 for example)
> - The decimal separator should be read from Windows
> - Find an "easy way" to localize the error messages (avoiding to redefine them for each control on a form).
> 
> ...


The tool is being released as is, and while I will fix obvious bugs, I do not intend to make major enhancements, since it meets my needs and I have for the most part moved on to other things.

I did not include the ErrorProvider within the control, because so much of it needs to be exposed to the external program and user interface preferences vary too widely for me to want to get into that.

The Keypress event level of control is not really necessary and will mislead you into thinking you have controlled user input when you haven't.  Paste Events completely disregard the Keypress event from a context menu and there is no way to manage the testing of pasted input in a completely separate path from typed input.  Validation of user typing has to account for highlighted text replacement by both typing and pasting and cancellation of input is already handled for the obvious issues.  The Keypress event is fine if a character is completely prohibited, but it does not work well if the key is permitted, but only in combination with other key strokes that follow.  Range validation is tricky, because you cannot cancel the many partial inputs that under a strict test can register as invalid on the way to the user typing a value that is required to achieve a valid input.

I have created a form that validates as the user types affecting multiple dependent controls just fine with this control through the project level.  So the messages and responses the control itself provides to the rest of the program work just fine for that style of validation without internalizing changes to the Keypress event.  I only use the ValueChanged event and it responds as the keys are pressed.  I feel it is fortunate I did not internalize this level of control, because in my actual projects I found normally that I have to suspend several validation tests until after the form is initially loaded and that is easily done through just the ValueChanged event.  The options I have provided should make it clear that I do not want to design a control that imposes the micromanagement of user behavior as the exclusive way to design an interface, but I think you will find that the control does not conflict with a project level design that needs to impose that level of restriction.

Localization of separator and decimal characters is specified by Windows settings, so it should do what you need.  Let me know if you find a case where that does not work and provide the configuration details so I can replicate it and test it.

I think the desire for an "easy way" to localize messages for multiple controls goes beyond the scope of the tool itself and is something to take up with Microsoft.

Implementation of a Tooltip should be no different than implementing it with any other control, as far as I know, but it was not something I attempted to implement.

----------


## CodeDabbler

I love this control and have used it in several projects to date.
However, I am unable to add it to the ToolBox in VS2015 Community edition.
Can anybody offer any suggestions?
Any help would be greatly appreciated.

----------


## jmcilhinney

> I love this control and have used it in several projects to date.
> However, I am unable to add it to the ToolBox in VS2015 Community edition.
> Can anybody offer any suggestions?
> Any help would be greatly appreciated.


I've never used the Community Edition so I don't know if anything is different there than other editions.  In other VS 2015 editions, you would first open a Windows Form in the designer, then right-click the desired section of the Toolbox and select "Choose Items", then browse for the DLL the control is defined in and then check the appropriate control.  Have you tried that?

----------


## CodeDabbler

> ... then right-click the desired section of the Toolbox and select "Choose Items", then browse for the DLL the control is defined in and then check the appropriate control.  Have you tried that?


I have, but it just does not show up in the toolbox.
It works in VS 2010Pro as described but in VS2015 Community.

----------


## jmcilhinney

> I have, but it just does not show up in the toolbox.
> It works in VS 2010Pro as described but in VS2015 Community.


Are you able to add any other controls from non-system assemblies?

----------


## CodeDabbler

> Are you able to add any other controls from non-system assemblies?


I created a UC in VS2010 Pro.
I can add it to VS2013 Community and VS2015 Community as described.
I CAN  add yoiurs in VS2013 Community, but not VS2015 Community.
I can add a reference in the project and use your NumberBox in VS2015Community, just cannot get it in the toolbox.
Any thoughts or ideas?

----------


## jmcilhinney

> Any thoughts or ideas?


None I'm afraid.

----------


## CodeDabbler

> None I'm afraid.


As a "backdoor" workaround...
I can start a new project
Open the location of the DLL
Drag the DLL to the Tool Box surface
Use as control as normal

The only thing that seems to be missing it the ToolboxBitmap, but that's obviously no big deal.

----------


## sgrya1

Hi,

Is there a way to determine if the control is left blank?
.value returns 0

----------


## jmcilhinney

> Hi,
> 
> Is there a way to determine if the control is left blank?
> .value returns 0


Um, it's a TextBox.  How would you usually test whether a TextBox is empty?

----------


## sgrya1

I was just jumping back on to delete my post.

There is no .text method to see if .text ="" but realised there is a .textlength to check if it's 0.

Thanks for your control. Very helpful.

----------


## CodeDabbler

> I was just jumping back on to delete my post.
> 
> There is no .text method to see if .text ="" but realised there is a .textlength to check if it's 0.
> 
> Thanks for your control. Very helpful.


You may also want to look at the BlankMode Property which accepts 3 Enum vals {Accept|ConvertToZero|Reject}

If set to Reject, you are unable to leave the control if its value it blank.

----------


## jmcilhinney

> I was just jumping back on to delete my post.
> 
> There is no .text method to see if .text ="" but realised there is a .textlength to check if it's 0.
> 
> Thanks for your control. Very helpful.


Firstly, Text is a property, not a method.  Secondly, of course there's a Text property.  Text is a member of the Control class so every control has a Text property.  Thirdly, I just took another look at the code, which I haven't looked at in a year or two at least, and I saw the NullableValue property, which includes this header:
vb.net Code:
''' <summary>    ''' Gets or sets the numeric value stored in the control.    ''' </summary>    ''' <value>    ''' A null reference if the control is blank; otherwise, a <see cref="Decimal" /> value.    ''' </value>
So, why are you asking me this question in the first place?  Read the code for yourself.  If that's too much trouble, don't use it.  I'm willing to help with actual problems.

----------


## larrycav

I have this tool installed in a VB2013 solution. I created a new solution and the tool doesn't appear in the toolbox and I don't see it in the list when I try to add it. Have the .vb file downloaded. How do I get the tool into my new solution toolbox?

----------


## jmcilhinney

> I have this tool installed in a VB2013 solution. I created a new solution and the tool doesn't appear in the toolbox and I don't see it in the list when I try to add it. Have the .vb file downloaded. How do I get the tool into my new solution toolbox?


I just tested to make absolutely sure that it would work as I expected and it did.  Here's what I did:

1. Downloaded both the NumberBox and SimpleNumberBox code files from post #1 in this thread.
2. Created a new Windows Forms Application project in VS 2013.
3. Right-clicked the project in the Solution Explorer and selected Add -> Existing Item.
4. Navigated to and selected the two downloaded code files.
5. Built the project.

After that, I opened the Toolbox and the two controls were added in a new section at the top.

----------


## larrycav

> I just tested to make absolutely sure that it would work as I expected and it did.  Here's what I did:
> 
> 1. Downloaded both the NumberBox and SimpleNumberBox code files from post #1 in this thread.
> 2. Created a new Windows Forms Application project in VS 2013.
> 3. Right-clicked the project in the Solution Explorer and selected Add -> Existing Item.
> 4. Navigated to and selected the two downloaded code files.
> 5. Built the project.
> 
> After that, I opened the Toolbox and the two controls were added in a new section at the top.


Thank you! 

I installed simplenumberbox because that's what I have been using in another project.  What is the difference between the that and numberbox?

----------


## jmcilhinney

> What is the difference between the that and numberbox?


From post #1:


> I've attached the class itself and a solution including the class in a DLL and a test application for putting the control through its paces. *I've also included a much simpler class for those with simpler needs.*


Less functionality but less complexity.

----------


## larrycav

> From post #1:Less functionality but less complexity.


Thank you.

----------


## new1

i dont know how can i use it
i add SimpleNumberBox.vb to my project and add textbox to the forum
but it still can type letters

----------


## jmcilhinney

> i dont know how can i use it
> i add SimpleNumberBox.vb to my project and add textbox to the forum
> but it still can type letters


You use it like any other control, i.e. you drag it from the Toolbox onto your form.  If you add a TextBox to your form then of course you can type letters into it.  If you want to use a SimpleNumberBox then you need to add a SimpleNumberBox, not a TextBox.

----------


## new1

very good tool
thanks alot for it

----------


## jmcilhinney

> very good tool
> thanks alot for it


Here to help.  :Smilie:

----------

