WPF中的数字数据输入

Mat*_*ton 65 c# wpf

您如何处理WPF应用程序中的数值输入?

没有NumericUpDown控件,我一直在使用TextBox并使用下面的代码处理它的PreviewKeyDown事件,但它非常难看.

有没有人发现更优雅的方式从用户那里获取数字数据而不依赖第三方控件?

private void NumericEditPreviewKeyDown(object sender, KeyEventArgs e)
{
    bool isNumPadNumeric = (e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) || e.Key == Key.Decimal;
    bool isNumeric = (e.Key >= Key.D0 && e.Key <= Key.D9) || e.Key == Key.OemPeriod;

    if ((isNumeric || isNumPadNumeric) && Keyboard.Modifiers != ModifierKeys.None)
    {
        e.Handled = true;
        return;
    }

    bool isControl = ((Keyboard.Modifiers != ModifierKeys.None && Keyboard.Modifiers != ModifierKeys.Shift)
        || e.Key == Key.Back || e.Key == Key.Delete || e.Key == Key.Insert
        || e.Key == Key.Down || e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up
        || e.Key == Key.Tab
        || e.Key == Key.PageDown || e.Key == Key.PageUp
        || e.Key == Key.Enter || e.Key == Key.Return || e.Key == Key.Escape
        || e.Key == Key.Home || e.Key == Key.End);

    e.Handled = !isControl && !isNumeric && !isNumPadNumeric;
}
Run Code Online (Sandbox Code Playgroud)

Arc*_*rus 56

怎么样:

protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
{
    e.Handled = !AreAllValidNumericChars(e.Text);
    base.OnPreviewTextInput(e);
}

private bool AreAllValidNumericChars(string str)
{
    foreach(char c in str)
    {
        if(!Char.IsNumber(c)) return false;
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

  • 这将在小数上失败.如果用户输入5.3.它也会因负数而失败,因为" - "不是数字.容易修复但只是想我会在那里谨慎. (8认同)
  • 为什么不Double.TryParse? (6认同)
  • e.Handled =!e.Text.ToCharArray().All(c => Char.IsNumber(c)); (5认同)
  • 我只是意识到这两种方法都不会阻止用户将非数字字符粘贴到控件中,但这不是一个大问题.我认为,我会将你的回答标记为答案'因为我们可以得到尽可能接近的答案.谢谢! (4认同)
  • e.Handled =!e.Text.All(Char.IsNumber); (3认同)

Eri*_*ric 13

我就是这样做的.它使用正则表达式来检查框中的文本是否为数字.

Regex NumEx = new Regex(@"^-?\d*\.?\d*$");

private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    if (sender is TextBox)
    {
        string text = (sender as TextBox).Text + e.Text;
        e.Handled = !NumEx.IsMatch(text);
    }
    else
        throw new NotImplementedException("TextBox_PreviewTextInput Can only Handle TextBoxes");
}
Run Code Online (Sandbox Code Playgroud)

现在有更好的方法在WPF和Silverlight中执行此操作.如果您的控件绑定到属性,您所要做的就是更改绑定语句.使用以下内容进行绑定:

<TextBox Text="{Binding Number, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"/>
Run Code Online (Sandbox Code Playgroud)

请注意,您也可以在自定义属性上使用此选项,如果框中的值无效并且控件将以红色边框突出显示,则您只需抛出异常即可.如果单击红色边框的右上角,则会弹出异常消息.

  • 我喜欢Regex解决方案.但问题是我无法在现有数字上添加减号,因为它假定新文本始终附加到旧文本.有什么建议吗? (2认同)

小智 10

我一直在使用附加属性来允许用户使用向上和向下键来更改文本框中的值.要使用它,你只需使用

<TextBox local:TextBoxNumbers.SingleDelta="1">100</TextBox>
Run Code Online (Sandbox Code Playgroud)

这实际上并没有解决这个问题中提到的验证问题,但它解决了我没有数字上/下控制的问题.使用它一点点,我想我可能真的比旧的数字上/下控制更好.

代码并不完美,但它处理我需要它处理的情况:

  • Up箭头,Down箭头
  • Shift + Up箭头,Shift + Down箭头
  • Page Up, Page Down
  • 绑定Converter文本属性

Code behind

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;

namespace Helpers
{
    public class TextBoxNumbers
    {    
        public static Decimal GetSingleDelta(DependencyObject obj)
        {
            return (Decimal)obj.GetValue(SingleDeltaProperty);
        }

        public static void SetSingleDelta(DependencyObject obj, Decimal value)
        {
            obj.SetValue(SingleDeltaProperty, value);
        }

        // Using a DependencyProperty as the backing store for SingleValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SingleDeltaProperty =
            DependencyProperty.RegisterAttached("SingleDelta", typeof(Decimal), typeof(TextBoxNumbers), new UIPropertyMetadata(0.0m, new PropertyChangedCallback(f)));

        public static void f(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            TextBox t = o as TextBox;

            if (t == null)
                return;

            t.PreviewKeyDown += new System.Windows.Input.KeyEventHandler(t_PreviewKeyDown);
        }

        private static Decimal GetSingleValue(DependencyObject obj)
        {
            return GetSingleDelta(obj);
        }

        private static Decimal GetDoubleValue(DependencyObject obj)
        {
            return GetSingleValue(obj) * 10;
        }

        private static Decimal GetTripleValue(DependencyObject obj)
        {
            return GetSingleValue(obj) * 100;
        }

        static void t_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            TextBox t = sender as TextBox;
            Decimal i;

            if (t == null)
                return;

            if (!Decimal.TryParse(t.Text, out i))
                return;

            switch (e.Key)
            {
                case System.Windows.Input.Key.Up:
                    if (Keyboard.Modifiers == ModifierKeys.Shift)
                        i += GetDoubleValue(t);
                    else
                        i += GetSingleValue(t);
                    break;

                case System.Windows.Input.Key.Down:
                    if (Keyboard.Modifiers == ModifierKeys.Shift)
                        i -= GetDoubleValue(t);
                    else
                        i -= GetSingleValue(t);
                    break;

                case System.Windows.Input.Key.PageUp:
                    i += GetTripleValue(t);
                    break;

                case System.Windows.Input.Key.PageDown:
                    i -= GetTripleValue(t);
                    break;

                default:
                    return;
            }

            if (BindingOperations.IsDataBound(t, TextBox.TextProperty))
            {
                try
                {
                    Binding binding = BindingOperations.GetBinding(t, TextBox.TextProperty);
                    t.Text = (string)binding.Converter.Convert(i, null, binding.ConverterParameter, binding.ConverterCulture);
                }
                catch
                {
                    t.Text = i.ToString();
                }
            }
            else
                t.Text = i.ToString();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


ero*_*ald 10

我决定使用LINQ表达式将标记为答案的答案简化为基本上2行.

e.Handled = !e.Text.All(Char.IsNumber);
base.OnPreviewTextInput(e);
Run Code Online (Sandbox Code Playgroud)