简体   繁体   English

WPF文本框验证删除其他数字之前的0

[英]WPF TextBox validation removes 0s before other digits

I'm implementing a validation rule for a property of type double bound to a TextBox. 我正在为绑定到TextBox的类型的属性实现验证规则。 The problem is that when I enter a 0 in the decimal digits, if the resulting number is accepted by the rule, WPF erases that last 0 as it understands it to be dummy mathematically. 问题是,当我在十进制数字中输入0时,如果结果数字被规则接受,则WPF会删除最后一个0,因为它认为这是数学上的伪数。 This prevents me from entering a non-0 digit after it. 这样可以防止我在其后输入非0的数字。

For example I cannot input 5.101 because when I reach 5.10, WPF erases the 0 and I get back to 5.1. 例如,我无法输入5.101,因为当我达到5.10时,WPF会擦除0,然后回到5.1。

I can workaround this by returning a failed ValidationResult when I catch 5.10, as in that case WPF does not remove the 0. But this is handled as a failure by the style (red border) and is confusing to the user. 我可以通过在捕获5.10时返回失败的ValidationResult来解决此问题,因为在这种情况下WPF不会删除0。但这被样式(红色边框)视为失败,并且会使用户感到困惑。

Any idea on a better workaround? 有更好的解决方法吗?

The validation is handled in a class inheriting from ValidationRule, and the Validate method is this. 验证是在从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);
        }
    }

The problem seems to be connected to feedback from the object. 问题似乎与对象的反馈有关。 When I change from TwoWay to something else, the validation no longer prevents the input of 0s. 当我从TwoWay更改为其他东西时,验证不再阻止输入0。 Unfortunately I do need the TextBox to display the content of my object the first time I bind it. 不幸的是,我确实需要TextBox在第一次绑定对象时显示对象的内容。 But after that I would be ok with just OneWayToSource as I can just reset the DataContext to update. 但是在那之后,我只需要OneWayToSource就可以了,因为我可以重置DataContext进行更新。 Is there a way for the TextBox to be filled with the property value when I attach the object to the DataContext, while in OneWayToSource (not by explicity setting its Text I mean)? 当我在OneWayToSource中将对象附加到DataContext时,是否有一种方法可以用属性值填充TextBox(不是通过显式设置其Text)?

I wish I knew WPF better to know for sure whether there's a better solution than this. 我希望我更好地了解WPF,以确保是否有比这更好的解决方案。 But note that you can provide your own IValueConverter to handle the conversion, and in doing so you can avoid the stripping of the trailing zero. 但请注意,您可以提供自己的IValueConverter来处理转换,并且这样做可以避免尾随零的剥离。 For example, this converter converts from the bound property to the control only once, ignoring all subsequent update events: 例如,此转换器仅将绑定属性转换为控件一次,而忽略所有后续更新事件:

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

This allows the control to be updated when your program first initializes the control, but after that it behaves as a one-way binding, only updating the source on changes. 这使您可以在程序首次初始化控件时对其进行更新,但之后它将作为单向绑定,仅在更改时更新源。

Frankly, it seems a little sneaky/hacky to me. 坦白说,对我来说似乎有点偷偷摸摸。 But it does work. 但这确实有效。 :) :)

I faced same issue with validation and Peter's answer was helpful to me. 我在验证时也遇到了同样的问题,Peter的回答对我很有帮助。 But it disables synchronization from source (model), in many cases it's not acceptable. 但是它禁用了源(模型)的同步,这在很多情况下是不可接受的。 I'm gone further and upgraded it a little. 我走得更远,升级了一点。 Be sure converter is markup extension or option x:Shared="False" used, in that case all bindings will use their own converter instances. 确保转换器是标记扩展或使用选项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 - base class to "converter as markup extension", XMath.Eq - just comparind floating point numbers with epsilon. ConverterBase - XMath.Eq为“转换器作为标记扩展名”的基类-仅将浮点数与epsilon进行比较。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM