【问题标题】:WPF TextBox validation removes 0s before other digitsWPF 文本框验证在其他数字之前删除 0
【发布时间】:2015-03-23 13:58:35
【问题描述】:

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

例如,我无法输入 5.101,因为当我达到 5.10 时,WPF 会擦除 0,然后我又回到 5.1。

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

有更好的解决方法的想法吗?

验证在一个继承自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 中(我的意思不是明确设置其文本)?

【问题讨论】:

  • 你能把你正在使用的代码贴出来吗?
  • 抱歉代码不可读,我正在研究如何以可读的方式显示它。
  • 只需编辑您的问题并使用代码格式化选项将代码放在那里。您不能在 cmets 中格式化代码。
  • 我不确定这是否有帮助,但您是否尝试过在绑定中使用格式字符串?像这样:stackoverflow.com/a/18362876/983064
  • 谢谢,我试过了,但字符串格式迫使我输入精确格式的数字,并且有一个烦人的行为。如果我想输入 5.1,当我按 5 时,它会自动带来指定数量的 0 数字,如果我输入 0.1,它不理解它并在添加 0 之前输入它。相当麻烦的行为。

标签: c# wpf validation textbox number-formatting


【解决方案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;
    }
}

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

坦率地说,这对我来说似乎有点偷偷摸摸/hacky。但它确实有效。 :)

【讨论】:

  • 确实有效,非常感谢!它可能很老套,但运行良好且易于管理。将其标记为已解决。
【解决方案2】:

我在验证方面遇到了同样的问题,彼得的回答对我很有帮助。但它会禁用来自源(模型)的同步,在许多情况下这是不可接受的。我走得更远,并对其进行了一些升级。确保转换器使用了标记扩展或选项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 进行比较。

【讨论】:

    猜你喜欢
    • 2012-03-30
    • 2013-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-18
    • 1970-01-01
    • 1970-01-01
    • 2015-04-21
    相关资源
    最近更新 更多