0

我基于 TextBox 编写了自定义控件,该控件还具有最小值和最大值输入,如下所示:

    public class NumericTextBox : TextBox
    {
        static NumericTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericTextBox), new FrameworkPropertyMetadata(typeof(NumericTextBox)));
        }


        public static readonly DependencyProperty MinimumProperty =
            DependencyProperty.Register("Minimum", typeof(int), typeof(NumericTextBox), new PropertyMetadata(default(int)));

        public int Minimum
        {
            get { return (int)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }

        public static readonly DependencyProperty MaximumProperty =
            DependencyProperty.Register("Maximum", typeof(int), typeof(NumericTextBox), new PropertyMetadata(100));

        public int Maximum
        {
            get { return (int)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }


        public new static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(int), typeof(NumericTextBox),
                                        new FrameworkPropertyMetadata(
                                            default(int),
                                            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                                            null,
                                            CoerceCurrentValue),
                                            IsValid);

        public new int Text
        {
            get { return (int)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }


        private static object CoerceCurrentValue(DependencyObject d, object baseValue)
        {
            var numericTextBox = (NumericTextBox)d;
            var intValue = (int)baseValue;
            if (intValue < numericTextBox.Minimum) intValue = numericTextBox.Minimum;
            if (intValue > numericTextBox.Maximum) intValue = numericTextBox.Maximum;

            if ((int)baseValue != intValue)
                numericTextBox.Text = intValue;

            return intValue;
        }

        private static bool IsValid(object value)
        {

            if (value == null)
                return false;

            int intValue;
            var result = Int32.TryParse(value.ToString(), out intValue);

            return result;


        }
}

在我的 xaml 中,我称之为:

<controls:NumericTextBox
    Grid.Row="0"
    Grid.Column="1"
    Margin="5"
    VerticalAlignment="Center"
    Text="{Binding Test, UpdateSourceTrigger=PropertyChanged}"
    Minimum="0"
    Maximum="100"
    />

它绑定到我的视图模型中的 Test 属性(作为 int )。一切正常,直到我输入一个字符并出现绑定错误:

System.Windows.Data 错误:7:ConvertBack 无法转换值“1a”(类型“字符串”)。绑定表达式:路径=文本;DataItem='NumericTextBox' (Name=''); 目标元素是'TextBox'(名称='');目标属性是“文本”(类型“字符串”) FormatException:“System.FormatException:输入字符串的格式不正确。在 System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal) 在 System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info) 在 System.String.System.IConvertible.ToInt32(IFormatProvider提供者)
在 System.Convert.ChangeType(对象值,类型转换类型,IFormatProvider 提供程序)在 MS.Internal.Data.SystemConvertConverter.ConvertBack(对象 o,类型类型,对象参数,CultureInfo 文化)在 System.Windows.Data.BindingExpression.ConvertBackHelper( IValueConverter 转换器,对象值,类型 sourceType,对象参数,CultureInfo 文化)'

可能是因为 TextBox 中的原始 Text 属性是字符串...但我不确定。请协助。

4

1 回答 1

1

你正在以错误的方式解决这个问题。您并没有将输入限制TextBox为仅限数字。框架正在尝试将 a 转换string为aint以适应您的new int Text属性,但正如错误所说:输入字符串的格式不正确。,例如。不是int. 尝试将其添加到构造函数中:

PreviewTextInput += new TextCompositionEventHandler((s, e) => e.Handled = 
    !e.Text.All(c => Char.IsNumber(c) && c != ' '));
PreviewKeyDown += new KeyEventHandler((s, e) => e.Handled = e.Key == Key.Space);

如果输入非数值,它们只需设置e.Handled为即可工作,这具有在这些情况下忽略输入的效果。true

此外,您不需要实现自己的Text属性......这只是令人困惑的事情。只需使用原始值并将值解析为int您需要的任何位置,请放心,它将一个数字。我认为这两个处理程序应该确保这一点。如果您有任何问题,请告诉我。

另一个想法是使用这些处理程序简单地创建一个AttachedProperty,然后您可以将其应用于任何TextBox控件。当然,你也需要实现你的MinimumMaximum属性AttachedProperties,但是你可以这样做:

<TextBox Text={Binding Test} Attached:TextBoxProperties.IsNumeric="True" 
    Attached:TextBoxProperties.Minimum="0" Attached:TextBoxProperties.Maximum="100" />

您可以从 MSDN 上的附加属性概述页面了解更多信息。

更新>>>

如果您不希望用户能够从 中删除最后一个字符TextBox,那么我们可以更改其中一个处理程序以禁止它:

PreviewKeyDown += PreviewKeyDown;
...
private void PreviewKeyDown(object sender, KeyEventArgs e)
{
    TextBox textBox = sender as TextBox;
    e.Handled = e.Key == Key.Space || 
    (textBox.Text.Length == 1 && (e.Key == Key.Delete || e.Key == Key.Back));
}
于 2013-10-06T14:46:52.393 回答