C# 验证错误阻止调用属性设置程序

C# 验证错误阻止调用属性设置程序,c#,wpf,validation,data-binding,xaml,C#,Wpf,Validation,Data Binding,Xaml,我正在寻找以下问题的简单解决方案: 我使用的是一个简单的TextBox控件,其文本属性绑定到代码隐藏中的属性。此外,我正在使用验证规则通知用户格式错误的输入 ... 此处显示样式时出错。。。 现在,在文本框中输入有效数据后,用户可以点击按钮发送数据。单击按钮时,将计算并发送代码隐藏中绑定属性用户名的数据 问题是用户可以在文本框中输入有效数据,这将在属性UserName中设置。如果用户随后决定更改文本框中的文本,并且数据变得无效,则在验证失败后不会调用属性用户名的setter 这意味着最后一个

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

我使用的是一个简单的TextBox控件,其文本属性绑定到代码隐藏中的属性。此外,我正在使用验证规则通知用户格式错误的输入

... 此处显示样式时出错。。。

现在,在文本框中输入有效数据后,用户可以点击按钮发送数据。单击按钮时,将计算并发送代码隐藏中绑定属性用户名的数据

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

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

我知道如果数据无效,我可以停用该按钮,事实上我是这样做的,但该方法是在UserName的setter中调用的。如果验证失败后未调用该按钮,则该按钮将保持启用状态


因此,问题是:如何在验证失败后启用属性设置程序的调用?

您可以将验证规则的属性设置为。这将首先更新源,然后执行验证。这意味着,即使验证失败,也应该调用属性设置程序。请注意,此属性仅在.NET 3.5 SP1以上版本中可用。有关更多详细信息,请参见(第1部分“如何使用它”。

如何在视图模型类中处理此问题:

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;
      }
   }
}
公共类MyViewModel:INotifyPropertyChanged,IDataErrorInfo
{
专用词典_Errors=新词典();
公共对象属性
{
获取{return\u SomeProperty;}
设置
{
if(value!=\u SomeProperty&!ValidationError(“SomeProperty”,value))
_SomeProperty=值;
OnPropertyChanged(“SomeProperty”);
}
}
}
私有布尔验证错误(字符串属性名称,对象值)
{
//我通常有一本映射属性的词典
//验证函数的名称;如果属性
//有效,如果无效,则显示错误消息。您可以嵌入验证逻辑
//当然,在属性设置器中,但是将它们作为单独的方法进行分解
//简化测试。
_错误[propertyName]=\u验证方法[propertyName](值);
OnPropertyChanged(“IsValid”);
}
公共布尔是有效的
{
获取{return!(_Errors.Where(x=>x.Value!=null.Any());
}
公共字符串此[string propertyName]
{
得到
{
返回(_Errors.ContainsKey(propertyName))
?_错误[propertyName]
:null;
}
}
}
一开始设置这一切有点尴尬,但一旦设置完毕,您就有了一种简单而直接的方法向UI报告验证错误(通过
DataErrorValidationRule
),一种直接的方法来知道任何给定属性是否有效(检查
\u errors
),以及告诉您整个视图模型是否有效的
IsValid
属性。(此外,您可以扩展
IsValid
属性,以处理视图模型的所有属性都有效但视图模型本身无效的情况,例如,两个互斥标志都已设置。)并且只要将它们设置为
内部
,就可以通过NUnit或其他方式对验证方法进行单元测试


我应该补充一点,上面的代码是我脑子里想不出来的,可能会也可能不会像写的那样工作——我的实际工作代码是在基类中的,并且有很多其他东西嵌入其中,这会让人困惑。

如何验证输入?在二传中?您的按钮是否使用CommandBinding?你能提供一些示例代码吗?不,没有命令绑定?setter中调用的验证方法只是检查绑定属性值的正确性,并设置按钮的启用状态。@HA:您能找到解决方案吗?我有完全相同的问题。标记的答案对我来说不是很清楚,谢谢你的提示。这似乎只起了部分作用。调用setter,但验证错误不会消失,即使输入了有效数据……我无法想象这是默认行为,因此这可能是由您的实现引起的。但是没有任何代码,很难帮助您。。。特别是因为您似乎要验证您的输入两次:一次使用ValidationRule,一次在属性设置器中,正如我从您对Jehof上述问题的评论中了解到的!?是的,我知道这是真的,不是最好的设计。如果我设置ValidationStep=“UpdatedValue”,那么验证规则的Validate方法将接收BindingExpression对象。如果没有设置,Validate将以字符串形式接收TextBox.Text内容。我不会说有两个验证阶段是不好的设计。在我看来,在ValidationRule中检查输入的值是否为正确的类型(例如,仅为数字)并在property setter中检查其余值绝对有意义。我的意思是,如果不提供任何代码,在这种情况下很难找到问题。然而,这似乎与ValidationStep非常相关,我不得不承认我对它不是很熟悉。我只知道它就在那里,我想给你一个暗示。我希望你能自己找到解决办法。网上应该有足够的信息。好的,谢谢。今晚我会读你回答的博客文章。也许这对我有帮助。谢谢你,罗伯特。这看起来确实很有趣,我会仔细看看