Results 1 to 3 of 3

Thread: [RESOLVED] Show Nothing In Disabled NumericUpDown

  1. #1

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Posts
    12,413

    Resolved [RESOLVED] Show Nothing In Disabled NumericUpDown

    I'm building a form that captures number of hours worked. This is a rewrite of a legacy application that didn't use proper controls to capture input, so one of the things that I'm doing is replacing TextBox controls used for capturing the hours with NumericUpDown controls instead.

    I need some custom logic for these controls that deviate slightly from the default UI. For example, I can accept up to 2 decimal places, but it should show the least number of decimals possible. The other thing is that if the value is zero, then don't show any value.

    In the designer, I have each NumericUpDown's BackgroundColor and ForeColor set to Window since their value starts at zero and then there's logic in the Enter/Leave that changes the ForeColor:
    Code:
    Private Sub NumericUpDowns_Enter(sender As Object, e As EventArgs) Handles NumericUpDownHours.Enter, NumericUpDownOvertime.Enter, NumericUpDownPremiumPay.Enter
        Dim nud As NumericUpDown = TryCast(sender, NumericUpDown)
        If (nud Is Nothing) Then
            Return
        End If
    
        nud.DecimalPlaces = 2 ' allow for 2 decimals
        nud.ForeColor = ForeColor ' show the value to the user
        Dim displayedValue As String = nud.Value.ToString("F2")
        nud.Select(0, displayedValue.Length) ' select the control
    End Sub
    
    Private Sub NumericUpDowns_Leave(sender As Object, e As EventArgs) Handles NumericUpDownHours.Leave, NumericUpDownOvertime.Leave, NumericUpDownPremiumPay.Leave
        Dim nud As NumericUpDown = TryCast(sender, NumericUpDown)
        If (nud Is Nothing) Then
            Return
        End If
    
        If (nud.Value = 0) Then
            ' hide the value from the user
            nud.ForeColor = nud.BackColor
        End If
    
        Dim decimalPlaces As Integer = 0 ' show 0 decimal places
        Dim value As String = nud.Value.ToString("F2")
        If (value(value.Length - 1) <> "0"c) Then
            decimalPlaces = 2 ' show 2 decimal places
        ElseIf (value(value.Length - 2) <> "0"c) Then
            decimalPlaces = 1 ' show 1 decimal places
        End If
    
        nud.DecimalPlaces = decimalPlaces
    End Sub
    The problem I'm running into is that NumericUpDownPremiumPay's Enabled property is driven by the state of a checkbox and when the NumericUpDown is disabled then the ForeColor is the disabled color instead of the BackColor.

    If you look at this picture, now how Hours and Overtime look empty, but Premium Pay does not.


    Edit - Eff it, I'm tired of trying to get the image to render in thread. Just open the link and get redirected I guess.
    Attached Images Attached Images  
    Last edited by dday9; Today at 10:27 AM.
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | HtmlLessons | CssLessons | Code Tags | Sword of Fury - Jameram

  2. #2
    PowerPoster
    Join Date
    Nov 2017
    Posts
    3,639

    Re: Show Nothing In Disabled NumericUpDown

    Just off the top of my head:

    Code:
        If (nud.Value = 0) Then
            ' hide the value from the user
            If (nud.Enabled = True) Then
                nud.ForeColor = nud.BackColor
            Else
                'Some sort of appropriate manipluation of ForeColor or BackColor to handle a disabled NUD
            End If
        End If

  3. #3

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Posts
    12,413

    Re: Show Nothing In Disabled NumericUpDown

    That's what I was doing, but the system was not respecting the ForeColor when it was disabled.

    Rather than hacking back/fore colors, I created a custom control that overrides the UpdateEditText method:
    Code:
    Namespace Controls
    
        Public Class NumericTextBox
            Inherits NumericUpDown
    
            Public Property HideValueOnZero As Boolean
    
            Private _maximumDecimalPlaces As Integer?
            Public Property MaximumDecimalPlaces As Integer?
                Get
                    Return _maximumDecimalPlaces
                End Get
                Set(value As Integer?)
                    If (value.HasValue AndAlso value.Value < 0) Then
                        Throw New ArgumentOutOfRangeException(NameOf(value))
                    End If
    
                    _maximumDecimalPlaces = value
                End Set
            End Property
    
            Public Sub New()
                HideValueOnZero = True
                _maximumDecimalPlaces = 2
            End Sub
    
            Protected Overrides Sub OnEnabledChanged(e As EventArgs)
                MyBase.OnEnabledChanged(e)
                UpdateEditText()
            End Sub
    
            Protected Overrides Sub OnEnter(e As EventArgs)
                MyBase.OnEnter(e)
    
                If (_maximumDecimalPlaces.HasValue) Then
                    ToggleDecimals(_maximumDecimalPlaces.Value)
                End If
                SelectValue()
                UpdateEditText()
            End Sub
    
            Protected Overrides Sub OnLeave(e As EventArgs)
                MyBase.OnLeave(e)
                UpdateEditText()
    
                If (_maximumDecimalPlaces.HasValue) Then
                    ToggleDecimals()
                End If
            End Sub
    
            Protected Overrides Sub OnValueChanged(e As EventArgs)
                MyBase.OnValueChanged(e)
                UpdateEditText()
            End Sub
    
            Protected Overrides Sub UpdateEditText()
                MyBase.UpdateEditText()
    
                If (HideValueOnZero AndAlso Value = 0 AndAlso Not ContainsFocus) Then
                    Dim internalTextBox As TextBox = GetInternalTextBox()
                    If (internalTextBox IsNot Nothing) Then
                        internalTextBox.Text = String.Empty
                    End If
                End If
            End Sub
    
            Private Function GetInternalTextBox() As TextBox
                Return Controls.OfType(Of TextBox).FirstOrDefault()
            End Function
    
            Private Sub SelectValue()
                Dim displayedValue As String = Value.ToString("F2")
                MyBase.Select(0, displayedValue.Length)
            End Sub
    
            Private Sub ToggleDecimals(Optional decimals As Integer? = Nothing)
                If (decimals.HasValue) Then
                    DecimalPlaces = decimals.Value
                    Return
                End If
    
                Dim places As Integer = 0
                Dim valueAsString As String = Value.ToString("F2")
                If (valueAsString(valueAsString.Length - 1) <> "0"c) Then
                    places = 2
                ElseIf (valueAsString(valueAsString.Length - 2) <> "0"c) Then
                    places = 1
                End If
    
                DecimalPlaces = places
            End Sub
    
        End Class
    
    End Namespace
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | HtmlLessons | CssLessons | Code Tags | Sword of Fury - Jameram

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width