How to prevent System.Windows.Forms.NumericUpDown from allowing to type non-digits when DecimalPlaces = 0?
I wish to make this WinForm
control (NumericUpDown
) enforce whole numbers conditionally depending on the type (whole vs floating) of the thing that I am working with.
If I set the DecimalPlaces = 0
, it displays 0, and then increments/decrements that by 1 when I click up/down. However, if I enter 0.6
, then it will display as 1, but will remain as 0.6
. If I subsequently increment it, the underlying but not displayed value will be 1.6.
I am looking for a simple, idiomatic way to enforce what I want (hopefully it is clear what I want). If I have to intercept some sort of event, then I will, but I hope to just rely on some flag/setting that the NumericUpDown
class already provides.
If your solution involves sub-classing NumericUpDown
, then I will have to think about that. At this stage in the release I would prefer a well-documented hack to a clean change that might cause bugs elsewhere. I would like to have the option of not sub-classing the NumericUpDown
.
Let m开发者_运维百科e know if you have questions, thanks.
The underlying value is of type decimal. The DecimalPlaces only affects the number of digits displayed in the control. The easiest way to achieve what you want is to round the NumericUpDown.Value to an int.
Here's an imperfect solution that we're using. First, prevent the user from typing a decimal (everything else the user might type seems to be handled by the control itself just fine):
Private Sub HandleKeyPress(sender As Object, e As Windows.Forms.KeyPressEventArgs) Handles MyNumericUpDown.KeyPress
If e.KeyChar = "."c Then e.Handled = True
End Sub
Second, prevent the user from pasting anything other than digits. Note that the approach I've taken hard-codes a couple of specific key combinations (ctrl-v and shift-insert). It doesn't handle other ways the user might paste, such as using the up-down control's context menu.
Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message,
ByVal keyData As System.Windows.Forms.Keys) As Boolean
If keyData = (Keys.Shift Or Keys.Insert) OrElse keyData = (Keys.Control Or Keys.V) Then
Dim data As IDataObject = Clipboard.GetDataObject
If data Is Nothing Then
Return MyBase.ProcessCmdKey(msg, keyData)
Else
Dim text As String = CStr(data.GetData(DataFormats.StringFormat, True))
If text = String.Empty Then
Return MyBase.ProcessCmdKey(msg, keyData)
Else
For Each ch As Char In text
If Not Char.IsNumber(ch) Then
Return True
End If
Next
Return MyBase.ProcessCmdKey(msg, keyData)
End If
End If
Else
Return MyBase.ProcessCmdKey(msg, keyData)
End If
End Function
This isn't the perfect solution, but it is close enough to the intended behavior for our needs.
精彩评论