验证错误会阻止调用属性设置器

时间:2010-05-11 07:47:38

标签: c# wpf validation data-binding xaml

我正在寻找以下问题的简单解决方案:

我正在使用一个简单的TextBox控件,其Text属性绑定到后面代码中的属性。另外,我使用验证规则来通知用户格式错误的输入。

                                                                 ...这里的错误显示风格......    

现在,在将有效数据输入TextBox后,用户可以点击按钮发送数据。单击该按钮时,将评估并发送后面代码中绑定属性UserName的数据。

问题是用户可以在TextBox中输入有效数据,这将在属性UserName中设置。如果用户随后决定更改TextBox中的文本并且数据变为无效,则在验证失败后不会调用属性UserName的setter。

这意味着最后一个有效数据保留在属性UserName中,而TextBox显示带有错误指示符的无效数据。如果用户然后单击按钮发送数据,将发送最后一个有效数据而不是当前TextBox内容。

我知道如果数据无效,我可以取消激活按钮,实际上我也可以,但是在UserName的setter中调用该方法。如果在验证失败后没有调用,则按钮保持启用状态。

所以问题是:如何在验证失败后启用属性设置器的调用?

2 个答案:

答案 0 :(得分:2)

我如何在我的视图模型类中处理它:

public class MyViewModel : INotifyPropertyChanged, IDataErrorInfo
{
   private Dictionary<string, string> _Errors = new Dictionary<string, string>();

   public object SomeProperty
   {
      get { return _SomeProperty; }
      set
      {
         if (value != _SomeProperty && !ValidationError("SomeProperty", value))
            _SomeProperty = value;
            OnPropertyChanged("SomeProperty");
         }
      }
   }

   private bool ValidationError(string propertyName, object value)
   {
      // I usually have a Dictionary<string, Func<object, string>> that maps property
      // names to validation functions; the functions return null if the property
      // is valid and an error message if not.  You can embed the validation logic
      // in the property setters, of course, but breaking them out as separate methods
      // eases testing.
      _Errors[propertyName] = _ValidationMethods[propertyName](value);
      OnPropertyChanged("IsValid");
   }

   public bool IsValid
   {
      get { return !(_Errors.Where(x => x.Value != null).Any()));
   }

   public string this[string propertyName]
   {
      get
      {
         return (_Errors.ContainsKey(propertyName))
            ? _Errors[propertyName]
            : null;
      }
   }
}

首先完成这一切设置有点尴尬,但是一旦完成,你就可以通过简单直接的方式向UI报告验证错误(通过DataErrorValidationRule),这很简单知道任何给定属性是否有效的方法(检查_Errors),以及告诉您整个视图模型是否有效的IsValid属性。 (另外,您可以扩展IsValid属性来处理视图模型的所有属性都有效但视图模型本身不是的情况,例如两个互斥的标志都被设置。)并且只要你使它们internal,验证方法可以通过NUnit或其他方式进行单元测试。

我应该补充一点,上面的代码不在我的脑海中,可能会或者可能不会像写的那样工作 - 我的实际工作代码是在基类中并且还有很多其他东西都被写入其中会让人感到困惑

答案 1 :(得分:1)

您可以将验证规则的ValidationRule.ValidationStep属性设置为ValidationStep.UpdatedValue。首先更新源,然后执行验证。这意味着,即使验证失败,也应调用属性设置器。请注意,此属性仅适用于.NET 3.5 SP1以上版本。有关详细信息,请参阅this blog post(“如何使用它?(第1部分)”段落。)