WPF TextBox 验证在其他数字之前删除 0
WPF TextBox validation removes 0s before other digits
我正在为绑定到 TextBox 的 属性 类型实施验证规则。问题是,当我在十进制数字中输入 0 时,如果规则接受结果数字,WPF 会删除最后一个 0,因为它认为它在数学上是虚拟的。这防止我在它后面输入非 0 数字。
例如,我无法输入 5.101,因为当我达到 5.10 时,WPF 会擦除 0,然后我回到 5.1。
我可以通过在捕获 5.10 时返回失败的 ValidationResult 来解决此问题,因为在这种情况下 WPF 不会删除 0。但这被样式(红色边框)处理为失败并且让用户感到困惑.
有更好的解决方法吗?
校验是在继承自ValidationRule的class中处理的,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 时,在 OneWayToSource 中(不是通过显式设置其文本,我的意思是),有没有办法让 TextBox 填充 属性 值?
我希望我能更好地了解 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;
}
}
这允许在您的程序第一次初始化控件时更新控件,但之后它表现为单向绑定,仅在更改时更新源。
坦率地说,对我来说似乎有点 sneaky/hacky。但它确实有效。 :)
我在验证方面遇到了同样的问题,Peter 的回答对我很有帮助。但是它禁用了来自源(模型)的同步,在许多情况下这是不可接受的。我走得更远,对它进行了一些升级。确保转换器使用了标记扩展或选项 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
- 基数 class 到 "converter as markup extension",XMath.Eq
- 只需将浮点数与 epsilon 进行比较。
我正在为绑定到 TextBox 的 属性 类型实施验证规则。问题是,当我在十进制数字中输入 0 时,如果规则接受结果数字,WPF 会删除最后一个 0,因为它认为它在数学上是虚拟的。这防止我在它后面输入非 0 数字。
例如,我无法输入 5.101,因为当我达到 5.10 时,WPF 会擦除 0,然后我回到 5.1。
我可以通过在捕获 5.10 时返回失败的 ValidationResult 来解决此问题,因为在这种情况下 WPF 不会删除 0。但这被样式(红色边框)处理为失败并且让用户感到困惑.
有更好的解决方法吗?
校验是在继承自ValidationRule的class中处理的,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 时,在 OneWayToSource 中(不是通过显式设置其文本,我的意思是),有没有办法让 TextBox 填充 属性 值?
我希望我能更好地了解 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;
}
}
这允许在您的程序第一次初始化控件时更新控件,但之后它表现为单向绑定,仅在更改时更新源。
坦率地说,对我来说似乎有点 sneaky/hacky。但它确实有效。 :)
我在验证方面遇到了同样的问题,Peter 的回答对我很有帮助。但是它禁用了来自源(模型)的同步,在许多情况下这是不可接受的。我走得更远,对它进行了一些升级。确保转换器使用了标记扩展或选项 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
- 基数 class 到 "converter as markup extension",XMath.Eq
- 只需将浮点数与 epsilon 进行比较。