当值设置回有效值时,ValidationRules不会删除错误

Jas*_*dge 5 c# wpf xaml user-controls validationrules

介绍

我创建了一个DecimalTextBox UserControl,它包含了我需要完成的一些十进制验证,因此我不需要每次都重新创建验证,而只需使用它UserControl.DependencyProperties根据Josh Smith的这篇文章,这个验证具有需要绑定的属性,因此我创建了所以我可以绑定它们.


问题

控件的验证表现得很奇怪.当我输入错误的值时TextBox,它会显示为错误.但是,当我尝试在代码中更改值时,文本框中显示的值保持不变.

以下是我执行导致此错误的步骤(在此示例中1是无效值):

  1. 加载表单,默认值为0.
  2. 在文本框中输入1(由于验证结果为错误,文本框变为红色)
  3. 在代码中,我将绑定到文本框的属性设置为0
  4. 表单仍然在红色文本框中显示1

代码示例

我准备了一个演示问题的例子,可以在这里下载.

我会在这里发布一些代码,如果你想要更多让我知道.

ValidationTestControl的XAML

<UserControl x:Class="WPFTestProject.ValidationTestControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:v="clr-namespace:WPFTestProject"
    x:Name="ValidationTest"
    Height="50" Width="525">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>          

    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
        <TextBlock Text="Type 'Banana' here: "></TextBlock>
        <TextBox MinWidth="100">
            <TextBox.Text>
                <Binding ElementName="ValidationTest"  Path="Text" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay" ValidatesOnDataErrors="True" ValidatesOnExceptions="True">
                    <Binding.ValidationRules>
                        <v:NotBananaValidationRule>
                            <v:NotBananaValidationRule.NotWhatBinding>
                                <v:NotBananaBinding x:Name="NotBananaValidationBinding"></v:NotBananaBinding>
                            </v:NotBananaValidationRule.NotWhatBinding>
                        </v:NotBananaValidationRule>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
        <TextBlock Text=" (the text will give error when = 'Banana')"></TextBlock>
    </StackPanel>
</Grid>
Run Code Online (Sandbox Code Playgroud)

ValidationTestControls代码背后

(是的,我知道不是很MVVM,但我觉得这个独立控制没问题)

 public partial class ValidationTestControl : UserControl
{
    public ValidationTestControl()
    {
        InitializeComponent();
        Banana = "Banana";

        Binding BananaBinding = new Binding("Banana");
        BananaBinding.Source = this;

        NotBananaValidationBinding.SetBinding(NotBananaBinding.NotWhatProperty, BananaBinding);
    }

    public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(ValidationTestControl), new PropertyMetadata());
    public static DependencyProperty BananaProperty = DependencyProperty.Register("Banana", typeof(string), typeof(ValidationTestControl), new PropertyMetadata());

    public string Text
    {
        get
        {
            return (string)GetValue(TextProperty);
        }
        set
        {
            SetValue(TextProperty, value);
        }
    }


    public string Banana
    {
        get
        {
            return (string)GetValue(BananaProperty);
        }
        set
        {
            SetValue(BananaProperty, value);
        }
    }


}
Run Code Online (Sandbox Code Playgroud)

为绑定创建了ValidationRule和FrameWorkElement

 public class NotBananaValidationRule:ValidationRule
{
    private NotBananaBinding _notWhatBinding;
    public NotBananaBinding NotWhatBinding
    {
        get { return _notWhatBinding; }
        set { _notWhatBinding = value; }
    }

    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        string what = value.ToString();

        if(what == _notWhatBinding.NotWhat||string.IsNullOrEmpty(what))
            return new ValidationResult(false,
                       "Please enter a string that is not " + _notWhatBinding.NotWhat);
        else
            return new ValidationResult(true, null);

    }

}


public class NotBananaBinding : FrameworkElement
{
    public static readonly DependencyProperty NotWhatProperty = DependencyProperty.Register(
      "NotWhat", typeof(string), typeof(NotBananaBinding), new UIPropertyMetadata());

    public string NotWhat
    {
        get { return (string)GetValue(NotWhatProperty); }
        set { SetValue(NotWhatProperty, value); }
    }

    public NotBananaBinding() { }
}
Run Code Online (Sandbox Code Playgroud)

基本上这个代码的作用是检查你是否输入了"Banana"然后返回验证错误.该控件公开依赖项属性,因为我希望能够在使用该控件时绑定它们.该FrameworkElement NotBananaBinding让我产生依赖性特性(因为它是一个DependencyObject用于验证,所以我可以绑定的东西.该有效性规则有NotBananaBinding存储的依赖属性,并用它在validate方法属性.

我知道我的财产名称有点蹩脚,对不起.问题在于该示例可以很好地显示错误.我急于做一个例子,我没有很好地命名变量.如果您发现代码很糟糕,请在 此处下载示例.


我的目标是什么呢?

基本上这个问题似乎是由于我实际上并没有改变这个值.

即使我在属性上调用OnPropertyChanged,因为值没有不同,它也不会尝试重新评估验证.

我可以明显地将值更改为某个任意有效值,然后将其更改为我想要的值并且它将起作用,但我希望有一些方法可以手动获取调用验证,重新评估值然后更改它把它换回来又有点乱.


结论

我做错了什么(可能是我从Josh Smiths帖子实现验证和绑定的方式)

这只是ac#bug,还是有意的行为?如果是这样,为什么?

有没有优雅的方法来解决它?

u_u

Sil*_*ind 1

验证会阻止Text设置该属性。在 setter 上放置一个断点,您会发现当您键入最后一个“a”时它不会中断。如果您输入 Bananan 并按 Backspace 并出现错误,请按下按钮,它将起作用。验证可确保您的属性中不存在无效值。因此,如果您在出错时将其保存到数据库中,它不会保存无效值。