How can I set a NumericUpDown control to display values as percentages?
You'll have to derive your own custom control and override the UpdateEditText()
method. While we're at it, let's override the default Minimum
, Maximum
, and Increment
property values to be a little more percentage-friendly.
We'll also need to override the base ParseEditText()
method to interpret the user-generated input as a percentage (dividing by 100), because the user will expect to enter 80
to represent 80%
(and the Decimal parser needs to ignore the percentage sign).
Public Class PercentUpDown
Inherits NumericUpDown
Private Shared ReadOnly DefaultValue As New [Decimal](0.0) ' 0%
Private Shared ReadOnly DefaultMinimum As New [Decimal](0.0) ' 0%
Private Shared ReadOnly DefaultMaximum As New [Decimal](1.0) ' 100%
Private Shared ReadOnly DefaultIncrement As New [Decimal](0.01) ' 1%
Public Sub New()
Value = DefaultValue
Minimum = DefaultMinimum
Maximum = DefaultMaximum
Increment = DefaultIncrement
End Sub
Protected Overrides Sub UpdateEditText()
If UserEdit Then
ParseEditText()
End If
Text = Value.ToString(String.Format("p{0}", DecimalPlaces))
End Sub
Protected Shadows Sub ParseEditText()
Debug.Assert(UserEdit = True, "ParseEditText() - UserEdit == false")
Try
If Not String.IsNullOrWhiteSpace(Text) AndAlso _
Not (Text.Length = 1 AndAlso Text.Equals("-")) Then
Value = Constrain(Decimal.Parse(Text.Replace("%", String.Empty), NumberStyles.Any, CultureInfo.CurrentCulture) / 100)
End If
Catch ex As Exception
' Leave value as it is
Finally
UserEdit = False
End Try
End Sub
Private Function Constrain(origValue As [Decimal]) As [Decimal]
Debug.Assert(Minimum <= Maximum, "minimum > maximum")
If origValue < Minimum Then Return Minimum
If origValue > Maximum Then Return Maximum
Return origValue
End Function
End Class
We could expand the scope of the class a little by adding a TextFormat
property where we could set the numeric display format we'd like to use at design time, so that we can support displaying the value as a Currency, for example.
The above code, though, is nice and compact and specifically targets Percentages, taking advantage of the existing DecimalPlaces
property. The Value
property is stored as the mathematical representation of the percentage (0.5 for 50%, for example), so it's simple to plug into a formula without worrying about dividing by 100.