locked
Overflow on NumericUpDown RRS feed

  • Question

  • I have a client who, believe it or not, wants integers that are 28 digits long (the maximum allowed in the decimal type).  When testing, I entered a longer integer, which exceeded the allowable range of the decimal type.  Immediately I got an overflow exception.

    I looked at the events associated with the NumericUpDown control and saw nothing that I could use to intercept this overflow.  As you know the NumericUpDown control returns a decimal value.

    Is there no way to intercept this so the value gets set to a valid high value; as it is now the program will simply crash??

    Thanks in advance for any help.

    Michael Bate

    • Moved by CoolDadTx Monday, November 23, 2015 2:53 PM Winforms related
    Sunday, November 22, 2015 11:29 PM

Answers

  • Hello,

    For a number that long it would seem prudent to also consider a TextBox if you are receiving an overflow even thou when I set the max to a value below the overflow limit the NumericUpDown abides by the max value set. 

    If we look at preventing this internally with Maximum set we never trigger a true for the condition below.

    Public Class MyNumericUpDown
        Inherits NumericUpDown
        ''' <summary>
        ''' We can do this in the hosting form too but when maximum is set
        ''' it is a moot point, we never get a true on the if statement even in 
        ''' Framework 2.
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Private Sub MyNumericUpDown_ValueChanged(sender As Object, e As EventArgs) Handles Me.ValueChanged
            If Value > 9999999999999999999999999999D Then
                Value = Maximum
            End If
        End Sub
    End Class

    Using the following custom TextBox, set Max characters via MaxLength, set AllowDecimals then to return the value use DecimalValue property.

    Compile this in your project

    Imports System.ComponentModel
    Public Class numericTextbox
        Inherits TextBox
    
        Const WM_PASTE As Integer = &H302
    
        <Category("Behavior"), _
        Description("Should decimals be allowed"), _
        DefaultValue(GetType(Integer), "1")> _
        Public Property AllowDecimals As Boolean
    
        <Browsable(False)>
        Public ReadOnly Property DecimalValue() As Decimal
            Get
                Return CDec(Text)
            End Get
        End Property
    
        Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
            Dim value As String = Me.Text
    
            value = value.Remove(Me.SelectionStart, Me.SelectionLength)
            value = value.Insert(Me.SelectionStart, e.KeyChar)
    
            If AllowDecimals Then
                e.Handled = CBool(value.LastIndexOf("-") > 0) _
                Or Not (Char.IsControl(e.KeyChar) OrElse
                Char.IsDigit(e.KeyChar) OrElse (e.KeyChar = "."c And Not _
                Me.Text.Contains(".") Or e.KeyChar = "."c And _
                Me.SelectedText.Contains(".")) OrElse (e.KeyChar = "-"c And Me.SelectionStart = 0))
            Else
                e.Handled = CBool(value.LastIndexOf("-") > 0) _
                Or Not (Char.IsControl(e.KeyChar) OrElse
                Char.IsDigit(e.KeyChar) OrElse (e.KeyChar = "-"c And Me.SelectionStart = 0))
            End If
    
            MyBase.OnKeyPress(e)
    
        End Sub
        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
            If m.Msg = WM_PASTE Then
                Dim value As String = Me.Text
                value = value.Remove(Me.SelectionStart, Me.SelectionLength)
                value = value.Insert(Me.SelectionStart, Clipboard.GetText)
                If AllowDecimals Then
                    Dim result As Decimal = 0
                    If Not Decimal.TryParse(value, result) Then
                        Return
                    End If
                Else
                    Dim result As Integer = 0
                    If Not Integer.TryParse(value, result) Then
                        Return
                    End If
                End If
    
            End If
            MyBase.WndProc(m)
        End Sub
    End Class
    

    Note before continuing the custom control disallows pasting invalid values from the Windows clipboard.

    Now add the control to a form and set MaxLength to say 28, set AllowDecimals to true e.g.

    NumericTextbox1.MaxLength = 28
    NumericTextbox1.AllowDecimals = True

    At any time get the text as a decimal

    NumericTextbox1.DecimalValue


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my webpage under my profile but do not reply to forum questions.
    Microsoft Developer tools
    Developer’s Guide to Windows 10 video series


    Saturday, November 28, 2015 10:47 AM
  • I thought that I replied to this before.

    The NumericUpDown control appears to convert the value entered by the user to decimal before comparing with the Maximum and Minimum and therefore raises an overflow exception before these comparisons.  I am using .Net Framework 2.0.  Maybe a later version fixes this, but the Maximum value does not deal with the problem when the user enters a huge value.

    I was unable to replicate the issue on Win7 64 bit system with app compiled to .Net 2.0 and either x86, x64 or AnyCPU.

    Like Matthew LEAN . D did I used Decimal.MinValue or Decimal.MaxValue for the minimum or maximum setting as when I tried to set those to either -79228162514264337593543950335 or 79228162514264337593543950335 an overflow occured. Even if I tried using

    CDec(-79228162514264337593543950335) or CDec(79228162514264337593543950335) an overflow occured. However using what Matthew LEAN .D used worked and I could paste from -79228162514264337593543950335 to 79228162514264337593543950335 in the NumericUpDown window and the NumericUpDown would accept that with no problem. Selecting the up arrow on the spinbox with the max value in the NumericUpDown window and nothing would happen but selecting the down arrow and negative increment would occur. Same with pasting negative max value in window except up arrow would increment but not down arrow.

    No matter how many digits were typed or pasted into the NumericUpDown window no issue occured with it. I even pasted text "Win7 64 bit system" into the window and nothing happened except the last value displayed in the window incremented when I selected an arrow in the spinbox.

    Also you use the term Long Integer and entering same. Was that via the NumericUpDown text window or via code attempting to set the NumericUpDown1 value to a Long Integer value?

    Option Strict On
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Location = New Point(CInt((Screen.PrimaryScreen.WorkingArea.Width / 2) - (Me.Width / 2)), CInt((Screen.PrimaryScreen.WorkingArea.Height / 2) - (Me.Height / 2)))
            NumericUpDown1.Minimum = Decimal.MinValue
            NumericUpDown1.Maximum = Decimal.MaxValue
            NumericUpDown1.DecimalPlaces = 2
            NumericUpDown1.Increment = 1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            MessageBox.Show(Decimal.MaxValue.ToString & vbCrLf & Decimal.MinValue.ToString)
        End Sub
    
    End Class

    Update: The below code works too.

    Option Strict Off
    Option Infer Off
    Option Explicit Off
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Location = New Point(CInt((Screen.PrimaryScreen.WorkingArea.Width / 2) - (Me.Width / 2)), CInt((Screen.PrimaryScreen.WorkingArea.Height / 2) - (Me.Height / 2)))
            NumericUpDown1.Minimum = CDec("-79228162514264337593543950335")
            NumericUpDown1.Maximum = CDec("79228162514264337593543950335")
            NumericUpDown1.DecimalPlaces = 2
            NumericUpDown1.Increment = 1
        End Sub
    
        Dim Temp As String = "79228162514264337593543950335"
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            MessageBox.Show(Decimal.MaxValue.ToString & vbCrLf & Decimal.MinValue.ToString)
            NumericUpDown1.Value = CDec(Temp)
        End Sub
    
    End Class


    La vida loca


    Saturday, November 28, 2015 2:41 PM

All replies

  • Can't you set the Maximum property on the control to stop it overflowing?

    And by the way, are you sure that a NumericUpDown is a good idea in this situation? I find it hard to imagine a user pressing the up arrow for a few thousand years to go through 28 digits.

    Monday, November 23, 2015 12:35 AM
  • Well I believe the Decimal type can represent 29 digits ahead of the decimal point according to Decimal Structure from positive 79,228,162,514,264,337,593,543,950,335 to negative 79,228,162,514,264,337,593,543,950,335. If you set the minimum value to 0 or if allowed -79228162514264337593543950335 and maximum value to 79228162514264337593543950335 then there should be no issue.

    The increment value would need to be considered also. I've never tested to see if a decimal can be entered by typing in the NumericUpDown with the increment set to 1 but entering a decimal value of perhaps 1.0000000002 or something to see what would happen.


    La vida loca

    Monday, November 23, 2015 12:46 AM
  • HI.

    there is not crash happen on my side. 

    input 

    -79228162514264337593543950335 or
    79228162514264337593543950335

        this.numericUpDown1.Increment = 0;
        this.numericUpDown1.Maximum = decimal.MaxValue;
        this.numericUpDown1.Minimum = decimal.MinValue;
        this.numericUpDown1.Controls[0].Visible = false;//hide the updown arrow
        this.numericUpDown1.InterceptArrowKeys = false;
        this.numericUpDown1.DecimalPlaces = 4;

    ...


    DON'T TRY SO HARD,THE BEST THINGS COME WHEN YOU LEAST EXPECT THEM TO.

    Monday, November 23, 2015 3:09 AM
  • I thought that I replied to this before.

    The NumericUpDown control appears to convert the value entered by the user to decimal before comparing with the Maximum and Minimum and therefore raises an overflow exception before these comparisons.  I am using .Net Framework 2.0.  Maybe a later version fixes this, but the Maximum value does not deal with the problem when the user enters a huge value.

    Thursday, November 26, 2015 5:30 AM
  • Hi. 

    decimal type has precision 28-29 significant digits

    if you need more bigger precision

    use 

    System.Numerics.BigInteger and parse TextBox's Text

    https://msdn.microsoft.com/en-us/library/vstudio/system.numerics.biginteger(v=vs.100).aspx


    DON'T TRY SO HARD,THE BEST THINGS COME WHEN YOU LEAST EXPECT THEM TO.

    Friday, November 27, 2015 2:41 AM
  • Hello,

    For a number that long it would seem prudent to also consider a TextBox if you are receiving an overflow even thou when I set the max to a value below the overflow limit the NumericUpDown abides by the max value set. 

    If we look at preventing this internally with Maximum set we never trigger a true for the condition below.

    Public Class MyNumericUpDown
        Inherits NumericUpDown
        ''' <summary>
        ''' We can do this in the hosting form too but when maximum is set
        ''' it is a moot point, we never get a true on the if statement even in 
        ''' Framework 2.
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Private Sub MyNumericUpDown_ValueChanged(sender As Object, e As EventArgs) Handles Me.ValueChanged
            If Value > 9999999999999999999999999999D Then
                Value = Maximum
            End If
        End Sub
    End Class

    Using the following custom TextBox, set Max characters via MaxLength, set AllowDecimals then to return the value use DecimalValue property.

    Compile this in your project

    Imports System.ComponentModel
    Public Class numericTextbox
        Inherits TextBox
    
        Const WM_PASTE As Integer = &H302
    
        <Category("Behavior"), _
        Description("Should decimals be allowed"), _
        DefaultValue(GetType(Integer), "1")> _
        Public Property AllowDecimals As Boolean
    
        <Browsable(False)>
        Public ReadOnly Property DecimalValue() As Decimal
            Get
                Return CDec(Text)
            End Get
        End Property
    
        Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
            Dim value As String = Me.Text
    
            value = value.Remove(Me.SelectionStart, Me.SelectionLength)
            value = value.Insert(Me.SelectionStart, e.KeyChar)
    
            If AllowDecimals Then
                e.Handled = CBool(value.LastIndexOf("-") > 0) _
                Or Not (Char.IsControl(e.KeyChar) OrElse
                Char.IsDigit(e.KeyChar) OrElse (e.KeyChar = "."c And Not _
                Me.Text.Contains(".") Or e.KeyChar = "."c And _
                Me.SelectedText.Contains(".")) OrElse (e.KeyChar = "-"c And Me.SelectionStart = 0))
            Else
                e.Handled = CBool(value.LastIndexOf("-") > 0) _
                Or Not (Char.IsControl(e.KeyChar) OrElse
                Char.IsDigit(e.KeyChar) OrElse (e.KeyChar = "-"c And Me.SelectionStart = 0))
            End If
    
            MyBase.OnKeyPress(e)
    
        End Sub
        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
            If m.Msg = WM_PASTE Then
                Dim value As String = Me.Text
                value = value.Remove(Me.SelectionStart, Me.SelectionLength)
                value = value.Insert(Me.SelectionStart, Clipboard.GetText)
                If AllowDecimals Then
                    Dim result As Decimal = 0
                    If Not Decimal.TryParse(value, result) Then
                        Return
                    End If
                Else
                    Dim result As Integer = 0
                    If Not Integer.TryParse(value, result) Then
                        Return
                    End If
                End If
    
            End If
            MyBase.WndProc(m)
        End Sub
    End Class
    

    Note before continuing the custom control disallows pasting invalid values from the Windows clipboard.

    Now add the control to a form and set MaxLength to say 28, set AllowDecimals to true e.g.

    NumericTextbox1.MaxLength = 28
    NumericTextbox1.AllowDecimals = True

    At any time get the text as a decimal

    NumericTextbox1.DecimalValue


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my webpage under my profile but do not reply to forum questions.
    Microsoft Developer tools
    Developer’s Guide to Windows 10 video series


    Saturday, November 28, 2015 10:47 AM
  • I thought that I replied to this before.

    The NumericUpDown control appears to convert the value entered by the user to decimal before comparing with the Maximum and Minimum and therefore raises an overflow exception before these comparisons.  I am using .Net Framework 2.0.  Maybe a later version fixes this, but the Maximum value does not deal with the problem when the user enters a huge value.

    I was unable to replicate the issue on Win7 64 bit system with app compiled to .Net 2.0 and either x86, x64 or AnyCPU.

    Like Matthew LEAN . D did I used Decimal.MinValue or Decimal.MaxValue for the minimum or maximum setting as when I tried to set those to either -79228162514264337593543950335 or 79228162514264337593543950335 an overflow occured. Even if I tried using

    CDec(-79228162514264337593543950335) or CDec(79228162514264337593543950335) an overflow occured. However using what Matthew LEAN .D used worked and I could paste from -79228162514264337593543950335 to 79228162514264337593543950335 in the NumericUpDown window and the NumericUpDown would accept that with no problem. Selecting the up arrow on the spinbox with the max value in the NumericUpDown window and nothing would happen but selecting the down arrow and negative increment would occur. Same with pasting negative max value in window except up arrow would increment but not down arrow.

    No matter how many digits were typed or pasted into the NumericUpDown window no issue occured with it. I even pasted text "Win7 64 bit system" into the window and nothing happened except the last value displayed in the window incremented when I selected an arrow in the spinbox.

    Also you use the term Long Integer and entering same. Was that via the NumericUpDown text window or via code attempting to set the NumericUpDown1 value to a Long Integer value?

    Option Strict On
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Location = New Point(CInt((Screen.PrimaryScreen.WorkingArea.Width / 2) - (Me.Width / 2)), CInt((Screen.PrimaryScreen.WorkingArea.Height / 2) - (Me.Height / 2)))
            NumericUpDown1.Minimum = Decimal.MinValue
            NumericUpDown1.Maximum = Decimal.MaxValue
            NumericUpDown1.DecimalPlaces = 2
            NumericUpDown1.Increment = 1
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            MessageBox.Show(Decimal.MaxValue.ToString & vbCrLf & Decimal.MinValue.ToString)
        End Sub
    
    End Class

    Update: The below code works too.

    Option Strict Off
    Option Infer Off
    Option Explicit Off
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Location = New Point(CInt((Screen.PrimaryScreen.WorkingArea.Width / 2) - (Me.Width / 2)), CInt((Screen.PrimaryScreen.WorkingArea.Height / 2) - (Me.Height / 2)))
            NumericUpDown1.Minimum = CDec("-79228162514264337593543950335")
            NumericUpDown1.Maximum = CDec("79228162514264337593543950335")
            NumericUpDown1.DecimalPlaces = 2
            NumericUpDown1.Increment = 1
        End Sub
    
        Dim Temp As String = "79228162514264337593543950335"
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            MessageBox.Show(Decimal.MaxValue.ToString & vbCrLf & Decimal.MinValue.ToString)
            NumericUpDown1.Value = CDec(Temp)
        End Sub
    
    End Class


    La vida loca


    Saturday, November 28, 2015 2:41 PM