WPF 验证规则阻止在文本框中输入小数点?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21004951/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF validation rule preventing decimal entry in textbox?
提问by bmt22033
I have a WPF textbox defined in XAML like this:
我有一个在 XAML 中定义的 WPF 文本框,如下所示:
<Window.Resources>
<Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<TextBox x:Name="upperLeftCornerLatitudeTextBox" Style="{StaticResource textBoxInError}">
<TextBox.Text>
<Binding Path="UpperLeftCornerLatitude" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:LatitudeValidationRule ValidationStep="RawProposedValue"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
As you can see, my textbox is bound to a decimal property on my business object called UpperLeftCornerLatitude which looks like this:
如您所见,我的文本框绑定到名为 UpperLeftCornerLatitude 的业务对象上的十进制属性,如下所示:
private decimal _upperLeftCornerLongitude;
public decimal UpperLeftCornerLatitude
{
get { return _upperLeftCornerLongitude; }
set
{
if (_upperLeftCornerLongitude == value)
{
return;
}
_upperLeftCornerLongitude = value;
OnPropertyChanged(new PropertyChangedEventArgs("UpperLeftCornerLatitude"));
}
}
My user will be entering a latitude value into this textbox and in order to validate that entry, I've created a validation rule that looks like this:
我的用户将在此文本框中输入纬度值,为了验证该条目,我创建了一个如下所示的验证规则:
public class LatitudeValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
decimal latitude;
if (decimal.TryParse(value.ToString(), out latitude))
{
if ((latitude < -90) || (latitude > 90))
{
return new ValidationResult(false, "Latitude values must be between -90.0 and 90.0.");
}
}
else
{
return new ValidationResult(false, "Latitude values must be between -90.0 and 90.0.");
}
return new ValidationResult(true, null);
}
}
My textbox initially starts off empty and I have a breakpoint set at the beginning of my validation rule. I enter 1 in the textbox and when my debugger breaks inside of the validation rule, I can see that value = "1". So far so good. Now I continue running and enter a decimal point in the textbox (so we should have "1." now). Again, the debugger breaks inside of the validation rule and, as expected, value = "1.". If I step through the validation rule code, I see that it passes the latitude value check and returns the following:
我的文本框最初是空的,我在验证规则的开头设置了一个断点。我在文本框中输入 1,当我的调试器在验证规则内中断时,我可以看到该值 =“1”。到现在为止还挺好。现在我继续运行并在文本框中输入小数点(所以我们现在应该有“1”)。同样,调试器在验证规则内部中断,正如预期的那样,value = "1."。如果我单步执行验证规则代码,我会看到它通过了纬度值检查并返回以下内容:
new ValidationRule(true, null);
However, as soon as the validation rule returns and I step into the next line of code, I find myself on the first line of my UpperLeftCornerLatitude property setter. Mousing over value here reveals that it's a value of "1" instead of "1." as I would expect. So naturally when I continue running my code, I end up back in the textbox staring at a value of "1" instead of "1.". If I remove all of the breakpoints, the effect is that I can't seem to enter a decimal point in the textbox. Is there something obvious that I'm missing here that's causing my setter to end up with a value of "1" even though I have entered "1." in the textbox? Thanks very much!
但是,一旦验证规则返回并进入下一行代码,我就会发现自己位于 UpperLeftCornerLatitude 属性设置器的第一行。将鼠标悬停在 value 上表明它是一个值“1”而不是“1”。正如我所料。所以很自然地,当我继续运行我的代码时,我最终回到文本框中,盯着值“1”而不是“1.”。如果我删除所有断点,效果是我似乎无法在文本框中输入小数点。是否有一些明显的东西我在这里遗漏了,导致我的 setter 以“1”的值结束,即使我输入了“1”。在文本框中?非常感谢!
回答by Shoe
Here are a few ways to fix this problem
这里有一些方法可以解决这个问题
A. Specify LostFocus (textbox default) for your binding
A. 为您的绑定指定 LostFocus(文本框默认值)
<Binding Path="UpperLeftCornerLatitude" Mode="TwoWay" UpdateSourceTrigger="LostFocus">
</Binding
B. Specify a Delayfor the binding that will allow for some time for you to type the decimal
B.Delay为绑定指定 a允许您在一段时间内输入小数
<Binding Path="UpperLeftCornerLatitude" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" Delay="1000">
</Binding
C. Change decimalto stringand parse it yourself
C.更改decimal到string和自己解析它
D. Write a ValueConverterto override the default conversion process
D. 写一个ValueConverter覆盖默认的转换过程
class DecimalConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
...
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
...
}
}
回答by Sheridan
.NET 4.5 UPDATE
.NET 4.5 更新
In .NET 4.5, Microsoft decided to introduce a breaking change to the way that data is entered into the TextBoxcontrol when the binding UpdateSourceTriggeris set to PropertyChanged. A new KeepTextBoxDisplaySynchronizedWithTextPropertyproperty was introduced that was supposedto recreate the previous behaviour... setting it to falseshouldreturn the previous behaviour:
在 .NET 4.5 中,TextBox当绑定UpdateSourceTrigger设置为.NET 时,Microsoft 决定对数据输入控件的方式进行重大更改PropertyChanged。KeepTextBoxDisplaySynchronizedWithTextProperty引入了一个新属性,它应该重新创建以前的行为……将其设置为false应该返回以前的行为:
FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty = false;
Unfortunately, although it allows us to enter a numerical separator again, it doesn't quite work as it used to. For example, the separator will still not appear in the TextBox.Textproperty value until it is followed by another number and this can cause issues if you have custom validation. However, it's better than a slap in the face.
不幸的是,虽然它允许我们再次输入数字分隔符,但它不像以前那样工作了。例如,分隔符仍然不会出现在TextBox.Text属性值中,直到它后面跟有另一个数字,如果您有自定义验证,这可能会导致问题。不过,总比一巴掌强。
回答by Matt
This really isn't going to be pretty, since WPF is going to automatically try to convert the string values to decimals as you type; I think this is due to the default Behavior<TextBox>. I think the simplestway for you to resolve this quickly would be to bind your control to a string property and expose another decimalproperty:
这真的不会很漂亮,因为 WPF 会在您键入时自动尝试将字符串值转换为小数;我认为这是由于默认Behavior<TextBox>. 我认为快速解决此问题的最简单方法是将控件绑定到字符串属性并公开另一个decimal属性:
private string _upperLeftCornerLongitudeStr;
public string UpperLeftCornerLatitudeStr
{
get { return _upperLeftCornerLongitudeStr; }
set
{
if (_upperLeftCornerLongitudeStr == value)
return;
_upperLeftCornerLongitudeStr = value;
OnPropertyChanged("UpperLeftCornerLatitudeStr");
}
}
public decimal? UpperLeftCornerLatitude
{
get
{
decimal val;
if (decimal.TryParse(_upperLeftCornerLongitudeStr, out val))
return val;
return null;
}
set { _upperLeftCornerLongitudeStr = value != null ? value.ToString() : null; }
}
That being said, you may want to look into different approaches that would prevent your used from entering invalid characters in the first place:
话虽如此,您可能想研究不同的方法来防止您使用的首先输入无效字符:
TextBox Input Behavior- A little more complex
文本框输入行为- 稍微复杂一点
回答by user3791372
For my use-case I have chosen to parse a decimal? as a string. I have used this code on the setter, so that if an invalid entry is entered, it isn't stored:
对于我的用例,我选择解析小数?作为字符串。我在 setter 上使用了此代码,因此如果输入了无效条目,则不会存储它:
public string Price {
get { return this._price.ToString(); }
set
{
if (value != null)
{
decimal p;
if (decimal.TryParse(value, out p))
{
this._price = (value);
this.NotifyPropertyChanged("Price");
}
}
}
}
回答by Marc Van Camp
In the validation rule code, return 'False'ValidationResult if the input value (as string) end with the NumberDecimalSeparator.
You'll be able to continue typing in the text box ...
在验证规则代码中,return 'False'如果输入值(作为字符串)以NumberDecimalSeparator. 您将能够继续在文本框中输入...
回答by Jonathan Shay
I've run into the same issue, and I believe it's caused by the attempt to set "1." to a decimal property. "1." does not parse to a valid decimal value.
我遇到了同样的问题,我相信这是由尝试设置“1”引起的。到十进制属性。“1。” 不解析为有效的十进制值。
Your options are to either
您的选择是
A) Remove the "UpdateSourceTrigger" from your TextBox's Text property binding. This will allow any text to be entered and validation is performed upon the TextBox losing focus;
A) 从 TextBox 的 Text 属性绑定中删除“UpdateSourceTrigger”。这将允许输入任何文本并在 TextBox 失去焦点时执行验证;
or
或者
B) Add your decimal point AFTER you've added your decimal values. For example, to enter "1.25", enter "125", then position the cursor between the "1" and the "2" and enter the ".". Tabbing off the control at this point yields a bound value of 1.25, which DOES parse to a valid decimal value.
B)在添加小数点后添加小数点。例如,要输入“1.25”,请输入“125”,然后将光标定位在“1”和“2”之间并输入“.”。此时关闭控件会产生 1.25 的边界值,它确实解析为有效的十进制值。

