创建一个只接受数字的WPF文本框

20

我想创建一个只接受特定范围内数值的文本框。 如何最好地实现这样的文本框?

我考虑继承TextBox并覆盖TextProperty的验证和强制转换。但是,我不确定如何做到这一点,而且我知道派生WPF控件通常不被推荐。


编辑:
我需要一个非常基本的文本框,可以过滤掉所有不是数字的按键输入。 最简单的方法是处理TextBox.PreviewTextInput事件:

private void textBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    int result;
    if (!validateStringAsNumber(e.Text,out result,false))
    {
        e.Handled = true;
    }
}

(validateStringAsNumber是我的函数,主要使用Int.TryParse)

一些建议的解决方案可能更好,但对于我需要的简单功能,这个解决方案是最容易且最快速实现的,而且已经足够满足我的需求。


1
请在此主题上查看我的问题:https://dev59.com/GHVD5IYBdhLWcg3wWaVh - Matt Hamilton
或者是这样: private void txtNumeric_PreviewTextInput(object sender, TextCompositionEventArgs e) { if (e.Text.Any(c=>!char.IsDigit(c))) e.Handled = true; } - Amer Sawan
5个回答

8
我看到的大多数实现都使用PreviewTextInput事件来实现正确的掩码行为。 这个继承自TextBox,这个使用附加属性。两者都使用.Net的MaskedTextProvider提供正确的掩码行为,但如果您只想要一个简单的“仅数字”文本框,则不需要此类。

6
private void txt_TextChanged(object sender, TextChangedEventArgs e)
{
    TextBox textBox = sender as TextBox;
    int iValue = -1;

    if (Int32.TryParse(textBox.Text, out iValue) == false)
    {
         TextChange textChange = e.Changes.ElementAt<TextChange>(0);
         int iAddedLength = textChange.AddedLength;
         int iOffset = textChange.Offset;

         textBox.Text = textBox.Text.Remove(iOffset, iAddedLength);
    }
}

1
当我使用上述代码时,我收到错误消息:“错误1:'System.Collections.Generic.ICollection<System.Windows.Controls.TextChange>'不包含定义为'ElementAt'的方法,也没有接受类型为'System.Collections.Generic.ICollection<System.Windows.Controls.TextChange>'的第一个参数的扩展方法'ElementAt'可以找到(您是否缺少使用指令或程序集引用?)NewProduct.xaml.cs 104 51 MediaStore"。缺少哪个引用? - HelloWorld1
@Legato 可能是不同的 .net 框架。 - stukselbax

4

我认为,实现这个要求的最佳方式是仅使用 OnTextChanged 事件,因为它可以处理来自按键的数字,也可以处理从剪贴板中复制+粘贴的数字。希望下面展示的 VB 代码能为此提供一些启示。

Private Sub NumericBox_TextChanged(sender As Object, e As TextChangedEventArgs) Handles Me.TextChanged
  Dim Buffer As New StringBuilder
  Dim Index As Integer = Me.SelectionStart
  For Each C In Me.Text
    If Char.IsDigit(C) Then
      Buffer.Append(C)
    ElseIf Me.SelectionStart > Buffer.Length Then
      Index -= 1
    End If
  Next
  Me.Text = Buffer.ToString
  Me.SelectionStart = Index
End Sub

0

最好的方法是使用覆盖方法OnKeyPressed来处理文本框。以下是使用静态字符方法IsDigit进行覆盖的代码。

if (!Char.IsDigit(e.KeyChar) && !Char.IsControl(e.KeyChar)) e.Handled = true;

这就是你真正需要做的。


唯一的问题是它不允许使用小数点(.)。 - Jason Ebersey
5
TextBox 只有 KeyDownPreviewKeyDown 两个事件,这两个事件的参数类型为 KeyEventArgs。该参数没有 KeyChar 属性,只有 Key 属性,可以从 Keys 枚举中获取一个键值。 - Javidan
4
如果有人想要从剪贴板粘贴一个数字,该怎么办? - Matt Becker

-1

这将是我的首选方法:

private void yearTxt_PreviewKeyDown(object sender, KeyEventArgs e)
{
  switch (e.Key)
  {
    case Key.D0:
    case Key.D1:
    case Key.D2:
    case Key.D3:
    case Key.D4:
    case Key.D5:
    case Key.D6:
    case Key.D7:
    case Key.D8:
    case Key.D9:
    case Key.NumLock:
    case Key.NumPad0:
    case Key.NumPad1:
    case Key.NumPad2:
    case Key.NumPad3:
    case Key.NumPad4:
    case Key.NumPad5:
    case Key.NumPad6:
    case Key.NumPad7:
    case Key.NumPad8:
    case Key.NumPad9:
    case Key.Back:
      break;
    default:
      e.Handled = true;
      break;
  }
}

如果您经常使用数字文本框,不想重复编写很多代码,可以这样做:
  1. 通过将Bryun的代码重命名为“numericTextBox”或类似的名称来创建一个方法。
  2. 在“PreviewKeyDown”事件中调用该方法,如下所示:
private void textBox1_PreviewKeyDown(object sender, KeyEventArgs e) { numericTextBox(sender, e); }
- matsolof
1
这个程序无法处理粘贴的文本或用户修改数字键并输入像$%^这样的字符。此外,用户也不能使用箭头键移动插入符号。 - Robin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接