Winforms 当小数位数=0时,如何防止System.Windows.Forms.NumericUpDown允许键入非数字?

Winforms 当小数位数=0时,如何防止System.Windows.Forms.NumericUpDown允许键入非数字?,winforms,.net-4.0,validation,numericupdown,decimal-point,Winforms,.net 4.0,Validation,Numericupdown,Decimal Point,我希望让这个WinForm控件(NumericUpDown)有条件地强制执行整数,具体取决于我正在处理的对象的类型(整型与浮动型) 如果我设置小数位数=0,它将显示0,然后在我单击向上/向下时将其递增/递减1。但是,如果输入0.6,则它将显示为1,但仍将保持为0.6。如果我随后增加它,则基础但未显示的值将为1.6 我正在寻找一种简单、惯用的方法来实现我想要的东西(希望我想要的东西很清楚)。如果我必须截获某种类型的事件,那么我会截获,但我希望只依赖NumericUpDown类已经提供的一些标志/设

我希望让这个
WinForm
控件(
NumericUpDown
)有条件地强制执行整数,具体取决于我正在处理的对象的类型(整型与浮动型)

如果我设置小数位数=0,它将显示0,然后在我单击向上/向下时将其递增/递减1。但是,如果输入
0.6
,则它将显示为1,但仍将保持为
0.6
。如果我随后增加它,则基础但未显示的值将为1.6

我正在寻找一种简单、惯用的方法来实现我想要的东西(希望我想要的东西很清楚)。如果我必须截获某种类型的事件,那么我会截获,但我希望只依赖
NumericUpDown
类已经提供的一些标志/设置

如果您的解决方案涉及到子分类
NumericUpDown
,那么我将不得不考虑这个问题。在发布的这个阶段,我更喜欢一个有良好文档记录的黑客,而不是一个可能在其他地方引起bug的干净的更改。我想选择不将
NumericUpDown
细分


如果您有任何问题,请告诉我,谢谢。

基础值为十进制类型。小数点仅影响控件中显示的位数。实现所需的最简单的方法是将NumericUpDown.Value四舍五入为int。

我们使用的是一个不完美的解决方案。首先,防止用户键入小数(用户可能键入的所有其他内容似乎都由控件本身处理得很好):

第二,防止用户粘贴数字以外的任何内容。请注意,我采用的方法是硬编码一些特定的组合键(ctrl-v和shift-insert)。它不处理用户可能粘贴的其他方式,例如使用上下控件的上下文菜单

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

这不是一个完美的解决方案,但它已经足够接近我们需要的预期行为了。

Andrei,你能更具体地说明如何做到这一点吗?更准确地说,我应该拦截哪个事件?我甚至不希望用户认为他们可以输入非整数值。我可以对值进行四舍五入,但我也不希望他们能够输入0.7-我希望它无法通过验证。您应该在使用它的任何地方对值进行四舍五入。或者,如果您想截取一个事件(并对其添加一些技巧),您可以截取ValueChanged事件,并在此处将该值修改为该事件的舍入部分(仅当它尚未舍入时-以避免无限循环!)Hm。。。这比破解TextChanged事件好吗?我不想默默地更正该值-我希望用户知道他们的输入不会被接受。我认为这样更好-但取决于您希望用户知道他们的输入不会被接受的方式。如果拦截ValueChanged,如果用户在按Enter键时输入1.6,则ValueChanged事件处理程序中的值将更改为2。另一方面,拦截TextChanged并不是一个好主意,因为此事件支持.NET Framework基础设施,不打算直接从您的代码中使用,而且它的事件处理程序将在用于引入1.6的字符上被调用,这很可能是一团乱。是的,这是.Net对初学者的把戏。看看这里的答案:看看它到底没有那么奇怪,至少,它是有记录的!:)
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