WPF TextBox验证在其他数字之前删除0

时间:2015-01-24 17:46:43

标签: c# wpf validation textbox number-formatting

我正在为一个绑定到TextBox的double类型的属性实现验证规则。问题是,当我在十进制数字中输入0时,如果规则接受了结果数字,WPF将删除最后的0,因为它理解它是数学上的虚拟。这可以防止我输入非0位数。

例如我无法输入5.101,因为当我达到5.10时,WPF会删除0并返回5.1。

我可以通过在捕获5.10时返回失败的ValidationResult来解决此问题,因为在这种情况下WPF不会删除0.但是这被处理为样式(红色边框)失败并且使用户感到困惑。 / p>

有关更好的解决方法的任何想法吗?

验证在继承自ValidationRule的类中处理,Validate方法就是这样。

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        double dValue = 0.0;
        string sValue;
        string definition = "Enter number in [ " + Min + "; " + Max + "]";

        // Catch non-double, empty, minus sign
        try
        {
            sValue = (string)value;
            if (sValue == "-")
                return new ValidationResult(false, definition);
            else if (sValue.Length > 0)
                dValue = double.Parse(sValue);
            else // Empty entry
                return new ValidationResult(false, definition);
        }
        catch (Exception ex)
        {
            return new ValidationResult(false, "Invalid entry: " + ex.Message);
        }

        // Forbid finishing with dot but return false to allow keyboard input
        if (sValue.EndsWith("."))
            return new ValidationResult(false, "Cannot end with '.'");

        // Check range
        if (dValue < Min || dValue > Max)
            return new ValidationResult(false, definition);
        else
        {
            // Workaround to allow input of 0
            if (sValue.Contains(".") && sValue.EndsWith("0"))
                return new ValidationResult(false, "Accepted");
            else
                return new ValidationResult(true, null);
        }
    }

问题似乎与来自对象的反馈有关。当我从TwoWay更改为其他内容时,验证不再阻止输入0。不幸的是,我确实需要TextBox在我第一次绑定它时显示我的对象的内容。但之后我就可以使用OneWayToSource,因为我可以重置DataContext进行更新。当我将对象附加到DataContext时,TextBox是否有一种方法可以填充属性值,而在OneWayToSource中(不是通过明确设置其文本我的意思)?

2 个答案:

答案 0 :(得分:1)

我希望我更了解WPF以确定是否有比这更好的解决方案。但请注意,您可以提供自己的IValueConverter来处理转换,这样做可以避免剥离尾随零。例如,此转换器仅从绑定属性转换为控件一次,忽略所有后续更新事件:

class DoubleToStringConverter : IValueConverter
{
    private bool _convert = true;

    public object Convert(object value,
        Type targetType, object parameter, CultureInfo culture)
    {
        return _convert ? value.ToString() : Binding.DoNothing;
    }

    public object ConvertBack(object value,
        Type targetType, object parameter, CultureInfo culture)
    {
        string text = value as string;
        double doubleValue;

        if (text != null &&
            targetType == typeof(double) &&
            double.TryParse((string)value, out doubleValue))
        {
            _convert = false;
            return doubleValue;
        }

        return Binding.DoNothing;
    }
}

这允许在程序首次初始化控件时更新控件,但之后它会表现为单向绑定,仅在更改时更新源。

坦率地说,对我来说,这似乎有点鬼鬼祟祟。但它确实有效。 :)

答案 1 :(得分:0)

我在验证时面临同样的问题,彼得的回答对我有帮助。但它禁用了源(模型)的同步,在许多情况下它是不可接受的。我走得更远,升级了一点。确保转换器是标记扩展或使用选项x:Shared="False",在这种情况下,所有绑定都将使用自己的转换器实例。

public class OptimizedDoubleToStringConverter : ConverterBase
{
   private double _prevValue;

   public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
   {
      if (!(value is double) && !(value is float))
         return null;

      return XMath.Eq(_prevValue, System.Convert.ToDouble(value))
            ? Binding.DoNothing
            : value.ToString();
   }

   public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
   {
      if (!(value is string))
         return null;

      double doubleValue = double.Parse(value.ToString());

      if (!XMath.Eq(_prevValue, doubleValue))
         _prevValue = doubleValue;

      return doubleValue;
   }
}

ConverterBase - 基类到“转换为标记扩展”,XMath.Eq - 只用epsilon比较浮点数。