在WPF中的数值数据输入

21 浏览
0 Comments

在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;
}

0
0 Comments

问题的出现原因:

该问题的出现是因为需要在WPF中实现数字数据输入,并且需要使用上下箭头来改变文本框中的值。作者使用了一个附加属性来实现这个功能,但这并没有解决验证问题,只是解决了没有数字上下控件时的问题。

解决方法:

为了解决这个问题,作者提供了一个附加属性TextBoxNumbers.SingleDelta,可以通过在XAML中使用该属性来实现数字数据输入。代码实现了以下功能:

- 使用上下箭头来增加或减少值

- 使用Shift + 上下箭头来以较大的步长增加或减少值

- 使用Page Up和Page Down键来以更大的步长增加或减少值

- 绑定文本属性的转换器

代码如下:

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);
        }
        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();
        }
    }
}

以上代码提供了一种在WPF中实现数字数据输入的方法,并解决了验证问题。

0
0 Comments

问题的原因:原先的解决方法是通过正则表达式来检查文本框中的内容是否为数字,但存在一个问题,即无法在现有数字后添加负号,因为该方法假设新文本总是附加到旧文本的末尾。

解决方法:使用WPF和Silverlight提供的更好的解决方法,即使用绑定验证。将控件绑定到属性,并使用特定的绑定语句。如果值无效,则抛出异常,控件将以红色边框进行突出显示。点击红色边框右上角可以弹出异常消息。

以下是具体代码实现:


这种绑定验证的方法比正则表达式解决方案更好。

0
0 Comments

在WPF中进行数字数据输入时,有一个问题出现。问题的原因是用户可以输入非数字字符,这可能导致数据不正确。为了解决这个问题,可以使用以下代码:

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;
}

这段代码在`OnPreviewTextInput`方法中进行处理。它将检查输入的文本是否只包含数字字符,如果不是,则设置`e.Handled`为`true`,这将阻止非数字字符输入。这种方法比其他方法更简洁,并且仍然允许使用控制键(如箭头键和退格键)。

然而,这种方法有一些限制。它无法阻止用户粘贴非数字字符到控件中。但是,目前来说这并不是一个大问题。如果需要处理粘贴非数字数据的情况,可以参考juanagui的答案(链接:http://stackoverflow.com/a/2673131/755404)。

此外,这段代码还存在一些其他问题。它无法处理小数和负数。如果用户输入了多个小数点或负号,代码将返回错误结果。不过,这些问题可以很容易地修复。可以使用以下代码来解决这些问题:

e.Handled = !e.Text.ToCharArray().All(c => Char.IsNumber(c));

或者

e.Handled = !e.Text.All(Char.IsNumber);

以上是解决WPF中数字数据输入的问题的方法和注意事项。希望对你有所帮助!

0