WPF验证规则阻止文本框中的小数输入?

bmt*_*033 6 c# validation wpf textbox

我有一个在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>
Run Code Online (Sandbox Code Playgroud)

如您所见,我的文本框绑定到我的业务对象上的一个名为UpperLeftCornerLatitude的十进制属性,如下所示:

private decimal _upperLeftCornerLongitude;
public decimal UpperLeftCornerLatitude
{
    get { return _upperLeftCornerLongitude; }
    set
    {
        if (_upperLeftCornerLongitude == value)
        {
            return;
        }

        _upperLeftCornerLongitude = value;
        OnPropertyChanged(new PropertyChangedEventArgs("UpperLeftCornerLatitude"));
    }
}
Run Code Online (Sandbox Code Playgroud)

我的用户将在此文本框中输入纬度值,为了验证该条目,我创建了一个如下所示的验证规则:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的文本框最初是空的,我在验证规则的开头设置了断点.我在文本框中输入1,当我的调试器在验证规则内部时,我可以看到value ="1".到现在为止还挺好.现在我继续运行并在文本框中输入一个小数点(所以我们现在应该有"1").同样,调试器在验证规则内部中断,并且如预期的那样,值="1".如果我单步执行验证规则代码,我会看到它通过了纬度值检查并返回以下内容:

new ValidationRule(true, null);
Run Code Online (Sandbox Code Playgroud)

但是,只要验证规则返回并且我进入下一行代码,我就会发现自己位于UpperLeftCornerLatitude属性setter的第一行.将鼠标置于价值上会显示它的值为"1"而不是"1".正如我所料.所以当我继续运行我的代码时,我自然会回到文本框中,盯着值"1"而不是"1".如果我删除所有断点,效果是我似乎无法在文本框中输入小数点.有没有明显的东西,我在这里失踪,这导致我的二传手最终得到一个值为"1",即使我已输入"1".在文本框中?非常感谢!

Sho*_*hoe 21

以下是解决此问题的几种方法

A.为绑定指定LostFocus(默认文本框)

<Binding Path="UpperLeftCornerLatitude" Mode="TwoWay" UpdateSourceTrigger="LostFocus">
</Binding
Run Code Online (Sandbox Code Playgroud)

B. Delay为绑定指定一个允许您输入小数的时间

<Binding Path="UpperLeftCornerLatitude" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" Delay="1000">
</Binding
Run Code Online (Sandbox Code Playgroud)

C.更改decimalstring和自己解析它

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)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你的回答.只是想指出,虽然选项B工作得非常好,但这有点风险.想象一下,用户有点分心,他开始输入"1",同时他正在检查一些文件,然后回到它,键入"23".但与此同时延迟过去了,小数点被删除了,所以应该是"1.23"现在是"123".涉及金钱时,这是完全不可取的.:) (9认同)

She*_*dan 5

.NET 4.5更新

在.NET 4.5中,Microsoft决定对TextBox绑定UpdateSourceTrigger设置为何时将数据输入控件的方式进行重大更改PropertyChanged.KeepTextBoxDisplaySynchronizedWithTextProperty引入了一个新属性,该属性应该重新创建以前的行为...将其设置为false 返回先前的行为:

FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty = false;
Run Code Online (Sandbox Code Playgroud)

不幸的是,尽管它允许我们再次输入数字分隔符,但它并不像以前那样工作.例如,分隔符仍然不会出现在TextBox.Text属性值中,直到它后跟另一个数字,如果您有自定义验证,这可能会导致问题.然而,它比脸上的一巴掌更好.