wpf文本框自定义控件类型错误

wpf文本框自定义控件类型错误,wpf,custom-controls,Wpf,Custom Controls,我在TextBox上编写了自定义控件,该控件还具有以下最小和最大输入: public class NumericTextBox : TextBox { static NumericTextBox() { DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericTextBox), new FrameworkPropertyMetadata(typeof(NumericTex

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


        }
}
公共类NumericTextBox:TextBox
{
静态NumericTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericTextBox),new FrameworkPropertyMetadata(typeof(NumericTextBox));
}
公共静态只读从属属性MinimumProperty=
DependencyProperty.Register(“最小”、typeof(int)、typeof(NumericTextBox)、new PropertyMetadata(默认值(int));
公共整数最小值
{
获取{return(int)GetValue(MinimumProperty);}
set{SetValue(MinimumProperty,value);}
}
公共静态只读从属属性MaximumProperty=
DependencyProperty.Register(“最大”、typeof(int)、typeof(NumericTextBox)、新PropertyMetadata(100));
公共整数最大值
{
获取{return(int)GetValue(MaximumProperty);}
set{SetValue(MaximumProperty,value);}
}
公共新静态只读DependencyProperty TextProperty=
DependencyProperty.Register(“文本”、typeof(int)、typeof(NumericTextBox),
新框架属性元数据(
默认值(int),
默认情况下,FrameworkPropertyMetadataOptions.BindsTwoWay,
无效的
强制电流值),
有效);
公共新整型文本
{
获取{return(int)GetValue(TextProperty);}
set{SetValue(TextProperty,value);}
}
私有静态对象强制当前值(DependencyObject d,object baseValue)
{
var numericTextBox=(numericTextBox)d;
var intValue=(int)baseValue;
如果(intValuenumericTextBox.max)intValue=numericTextBox.max;
如果((int)baseValue!=intValue)
numericTextBox.Text=intValue;
返回值;
}
私有静态bool有效(对象值)
{
如果(值==null)
返回false;
int值;
var result=Int32.TryParse(value.ToString(),out intValue);
返回结果;
}
}
在我的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” (键入“String”)。BindingExpression:Path=Text; DataItem='NumericTextBox'(名称='';目标元素是“TextBox” (名称=“”);目标属性为“Text”(类型为“String”) FormatException:'System.FormatException:输入字符串不在 格式正确。在System.Number.StringTonNumber(字符串str, NumberStyles选项、NumberBuffer&number、NumberFormatInfo信息、, System.Number.ParseInt32(字符串s, NumberStyles样式,NumberFormatInfo)位于 System.String.System.IConvertible.ToInt32(IFormatProvider)
在System.Convert.ChangeType(对象值、类型转换类型、, IFormatProvider)位于 MS.Internal.Data.SystemConvertConverter.ConvertBack(对象o,类型 类型、对象参数、CultureInfo区域性)位于 System.Windows.Data.BindingExpression.ConvertBackHelper(IValueConverter 转换器、对象值、类型sourceType、对象参数、, 文化信息(文化)'

这可能是因为TextBox中的原始文本属性是字符串。。。但我不确定。
请帮忙。

你做得不对。您没有将
文本框的输入限制为仅输入数字。框架正在尝试将
字符串
转换为
int
,以适合
新的int文本
属性,但正如错误所述:输入字符串的格式不正确,例如,不是
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
控件。当然,您还需要将
最小值
最大值
属性实现为
AttachedProperties
,但是您可以这样做:

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

您的解决方案不依赖于依赖项属性绑定特性,而是依赖于PreviewKeyDown事件。我更喜欢使用DP验证和强制功能。这样,我可以在文本框周围有一个红色边框来表示不正确的值。例如,你更愿意让用户输入不正确的值并提醒他们这一事实,而不是简单地不允许他们输入不正确的值?有趣。要做到这一点,我宁愿使用或界面来提供完整的用户反馈。然而,选择当然是你的。这是一个UI设计的问题。。。例如,用户应该如何知道只允许数字。IDataErrorInfo也是一个显示通用消息的选项,如“只允许数字”-但同样,它应该在自定义控件上实现,而不是在视图模型上实现。你的解决方案很好,但是。。。我可能会坚持下去。但是
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));
}