Validation数据验证DataAnnotation机制和调试技巧

最后更新于:2022-04-01 14:20:56

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 在学习了[Silverlight Validation数据验证基础属性和事件](http://www.cnblogs.com/jv9/archive/2010/09/09/1821891.html)后,大家对Silverlight数据验证应该有了一个简单明了的认识。今天,我将继续介绍另外一种Silverlight的Validation验证机制,DataAnnotation。 在文章开始前,我想首先介绍一下Visual Studio中如何调试Silverlight的Validation代码。 Visual Studio 2010调试Silverlight Validation设置技巧* 相信大家在运行上一篇的代码时会发现,在异常出现时,Visual Studio会自动中断和获取当前异常错误信息,这为调试带来了一些不便。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc33865.jpg) 针对以上问题,我们可以在Visual Studio中进行简单设置,暂时取消在Debug模式下对异常的捕获,方法如下: 首先到Debug菜单,选择Exceptions菜单,也可以使用“Ctrl+Alt+E”,激活Exception窗口 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc42b33.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc56021.jpg) 点击“Find”查找以下选项, System.Exception,将其后面的CheckBox取消选中, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc6e9e4.jpg) 这样就实现了当数据验证时,Visual Studio不再捕获异常错误。 对于本篇,我们将使用DataAnnotation验证机制,该验证机制与[上一篇](http://www.cnblogs.com/jv9/archive/2010/09/09/1821891.html)略有不同,所以,如果要实现Visual Studio忽略捕获异常,要另外在Exception窗口搜索“System.ComponentModel.DataAnnotations.ValidationException",同样将其后面的CheckBox取消选中。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc7e667.jpg) Visual Studio 2008和Silverlight 3开发环境中,默认情况下Exception没有System.ComponentModel.DataAnnotations.ValidationException选项,开发人员可以自行添加一个新的异常即可,点击“Add”按钮, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc8e569.jpg) 在完成以上的操作后,再次执行Silverlight应用调试Validation时,Visual Studio不再出现异常捕获,相对方便很多。 [Silverlight DataAnnotation](http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx)验证机制 **验证Metadata属性** Silverlight的DataAnnotation验证机制是Silverlight 3发布WCF RIA Services测试版是推出的客户端验证机制,对于DataAnnotation的翻译,可以理解为“数据元素注释”验证法。该验证机制,使用了System.ComponentModel.DataAnnotations命名空间中的属性类,通过对DataMember数据成员设置Metadata元数据属性,对其验证值进行判断是否符合当前属性条件,以达到Validation的效果。该验证机制,多数运用于WCF RIA Services应用中. ~~~           private string _email;           [Required(ErrorMessage = "必填选项")]           public string email           {               get { return _email; }               set                {                   _email = value;                }          } ~~~ 从上面代码可以看到属性上面的注释 [Required(ErrorMessage = "必填选项")],该注释就是DataAnnotations类中的固有属性,其结果是判断该控件内容是否为空,如果是,则弹出异常。目前常用的DataAnnotation属性如下列表: <table class="MsoTableGrid" style="border-collapse: collapse; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-yfti-tbllook: 1184; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt;" border="1" cellspacing="0" cellpadding="0"><tbody><tr style="height: 29.55pt; mso-yfti-irow: 0; mso-yfti-firstrow: yes;"><td style="padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 92.8pt; padding-right: 5.4pt; height: 29.55pt; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; border: black 1pt solid;" width="124"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><strong style="mso-bidi-font-weight: normal;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">属性名称</span><span lang="EN-US"/></strong></p></td><td style="border-bottom: black 1pt solid; border-left: #f0f0f0; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 244.7pt; padding-right: 5.4pt; height: 29.55pt; border-top: black 1pt solid; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-left-alt: solid black .5pt; mso-border-left-themecolor: text1;" width="326"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><strong style="mso-bidi-font-weight: normal;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">描述</span><span lang="EN-US"/></strong></p></td></tr><tr style="height: 29.55pt; mso-yfti-irow: 1;"><td style="border-bottom: black 1pt solid; border-left: black 1pt solid; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 92.8pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1;" width="124"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;">Required</span></span></p></td><td style="border-bottom: black 1pt solid; border-left: #f0f0f0; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 244.7pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-left-alt: solid black .5pt; mso-border-left-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1; mso-border-right-themecolor: text1;" width="326"><p class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0pt;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">标识该属性为必需参数,不能为空</span><span lang="EN-US"/></p></td></tr><tr style="height: 29.55pt; mso-yfti-irow: 2;"><td style="border-bottom: black 1pt solid; border-left: black 1pt solid; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 92.8pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1;" width="124"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;">StringLength</span></span></p></td><td style="border-bottom: black 1pt solid; border-left: #f0f0f0; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 244.7pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-left-alt: solid black .5pt; mso-border-left-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1; mso-border-right-themecolor: text1;" width="326"><p class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0pt;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">标识该字符串有长度限制,可以限制最小或最大长度</span><span lang="EN-US"/></p></td></tr><tr style="height: 29.55pt; mso-yfti-irow: 3;"><td style="border-bottom: black 1pt solid; border-left: black 1pt solid; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 92.8pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1;" width="124"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;">Range</span></span></p></td><td style="border-bottom: black 1pt solid; border-left: #f0f0f0; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 244.7pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-left-alt: solid black .5pt; mso-border-left-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1; mso-border-right-themecolor: text1;" width="326"><p class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0pt;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">标识该属性值范围,通常被用在数值型和日期型</span><span lang="EN-US"/></p></td></tr><tr style="height: 29.55pt; mso-yfti-irow: 4;"><td style="border-bottom: black 1pt solid; border-left: black 1pt solid; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 92.8pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1;" width="124"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;">RegularExpression</span></span></p></td><td style="border-bottom: black 1pt solid; border-left: #f0f0f0; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 244.7pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-left-alt: solid black .5pt; mso-border-left-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1; mso-border-right-themecolor: text1;" width="326"><p class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0pt;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">标识该属性将根据提供的正则表达式进行对比验证</span><span lang="EN-US"/></p></td></tr><tr style="height: 29.55pt; mso-yfti-irow: 5; mso-yfti-lastrow: yes;"><td style="border-bottom: black 1pt solid; border-left: black 1pt solid; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 92.8pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1;" width="124"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;">CustomValidation</span></span></p></td><td style="border-bottom: black 1pt solid; border-left: #f0f0f0; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 244.7pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-left-alt: solid black .5pt; mso-border-left-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1; mso-border-right-themecolor: text1;" width="326"><p class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0pt;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">标识该属性将按照用户提供的自定义验证方法,进行数值验证</span><span lang="EN-US"/></p></td></tr></tbody></table> 在随后的实例中,我们将一一演示这些属性的使用方法。 **ValidationContext和Validator类** 阅读过上一篇Silverlight Validation基础的朋友应该知道,Silverlight的数据验证,可以在数据成员的Setter中设置条件验证,根据其验证结果判断是否符合验证。例如: ~~~           private int _age;           public int Age           {               get { return _age; }               set               {                   if (value > 100 || value < 0)                   {                       throw new Exception("请输入年龄值在0 - 100之间.");                  }                  _age = value;              }          } ~~~ 在set中,判断年龄值是否超过100岁或者低于0岁,如果不符合条件,则抛出异常,该异常将被Validation机制捕获,并显示到UI。 而Silverlight的DataAnnotation机制,与上面验证方法不同。Silverlight的DataAnnotation验证机制,在添加验证属性后,不需要在Setter中进行验证判断,仅需要在Setter中激活该验证属性即可,而要实现激活验证,则需要使用ValidationContext和Validator类。为了更好的理解Silverlight DataAnnotation验证机制,我们来对这两个类进行简单的讲解, 首先说说[Validator类](http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validator.aspx),该类是一个静态类,主要用来当数据成员被指定验证元数据属性时,验证对象,属性和方法。简单的理解就是包含了各种具体验证方法的类。例如上文代码,我们使用了Require验证属性,Validator类将会根据该验证属性执行对应的验证方法,对目标值进行判断。在该类中,包含ValidateProperty方法和TryValidateProperty方法,可以分别对当前属性进行验证操作。 而[ValiationContext类](http://msdn.microsoft.com/en-us/library/dd382177.aspx),该类是对当前执行的数据验证提供上下文描述的。简单的理解,也就是为验证提供数据传输,属性标识等任务。 我们对email属性,进行简单的修改,添加以上两个类,让该属性Silverlight的DataAnnotation机制生效。 ~~~           private string _email;           [Required(ErrorMessage = "必填选项")]           public string email           {               get { return _email; }               set                {                   var tmpValidator = new ValidationContext(this, null, null);                   tmpValidator.MemberName = "email";                  Validator.ValidateProperty(value, tmpValidator);                  _email = value;               }          } ~~~ 在上文代码中,我们定义一个ValidationContext实例,该实例中包含了需要验证对象的引用,并且,我们定义了验证对象的MemberName,通过调用Validator.ValidateProperty静态方法,检查目标数据是否符合当前验证属性,如果返回False,则抛出一个ValidationException。 上面代码也可简写为: ~~~ Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "email" }); ~~~ 当运行实例后,输入空格在邮件文本框中,Silverlight的DataAnnotation验证机制将被激活,生成如下效果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc9dd9d.jpg) 在理解了上面的Silverlight的DataAnnotation验证机制的基本类和属性后,我们可以做几个简单的实例,来加深理解。 1. StringLength,定义Password密码框最大可输入6个字符, ~~~              <StackPanel Orientation="Horizontal" Margin="5">                  <TextBlock Text="密   码: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtPassword" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=password, Mode=TwoWay,ValidatesOnExceptions=True, NotifyOnValidationError=True}" />              </StackPanel> ~~~ ~~~           private string _password;           [StringLength(6, ErrorMessage="密码不能超过6个字符")]           public string password           {               get { return _password; }               set                {                   Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "password" });                   _password = value;               }          } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ccaef0b.jpg) 2. Range,我们使用Range属性设置Age年龄的有效范围, ~~~  <StackPanel Orientation="Horizontal" Margin="5">                  <TextBlock Text="年   龄: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtAge" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=Age, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}" />              </StackPanel> ~~~ ~~~           private int _age;           [Range(0, 100, ErrorMessage = "请输入年龄值在0 - 100之间")]           public int Age           {               get { return _age; }               set               {                   Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Age" });                  _age = value;              }          } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ccc484a.jpg) 3. RegularExpression,我们使用正则表达式属性,验证邮件输入框。 ~~~  <StackPanel Orientation="Horizontal" Margin="5">                  <TextBlock Text="邮   件: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtEmail" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=email, Mode=TwoWay, ValidatesOnNotifyDataErrors=False, NotifyOnValidationError=True, ValidatesOnExceptions=True}" />              </StackPanel> ~~~ ~~~           private string _email;           [Required(ErrorMessage = "必填选项")]           [RegularExpression(@"^([0-9a-zA-Z]([-./w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-/w]*[0-9a-zA-Z]/.)+[a-zA-Z]{2,9})$",ErrorMessage="请输入正确的Email格式")]           public string email           {               get { return _email; }               set                {                   var tmpValidator = new ValidationContext(this, null, null);                  tmpValidator.MemberName = "email";                  Validator.ValidateProperty(value, tmpValidator);                  _email = value;               }          } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ccd38a6.jpg) 4. 自定义验证方法的应用 我们创建一个简单的自定义验证方法,验证用户名是否为jv9. 首先创建自定义验证类,CustomizeValidation,在类中添加引用,using System.ComponentModel.DataAnnotations; 然后继承ValidationAttribute类,使其预定义该类为自定义验证属性, 完成上面的设置后,即可创建自定义验证方法。 ~~~      public class CustomizeValidation : ValidationAttribute      {          protected override ValidationResult IsValid(object value, ValidationContext validationContext)          {              String checkName = value.ToString();                return checkName == "jv9" ? ValidationResult.Success : new ValidationResult("请使用指定用户名");          }      } ~~~ 在Name属性中,进行调用, ~~~           private string _name;           [CustomizeValidation]           public string Name           {               get { return _name; }               set                {                   Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Name" });                   if (string.IsNullOrEmpty(value))                  {                      throw new Exception("用户名不能为空.");                  }                  _name = value;               }          } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cce6577.jpg) 对于Silverlight的DataAnnotation验证机制,相比其他验证机制使用起来较为简单,但是其本身具有一定局限性。特别是当数据成员来自服务器端,会因为类库无法共享使用造成无法正常验证。前文曾提及,该验证机制多数用在WCF RIA Services,因为WCF RIA应用提供的数据层,可生成对应客户端代码,即可实现在客户端的DataAnnotation验证。在随后的实例中,我将演示一套WCF RIA服务下的验证实例。 今天讲到这里,希望大家能够有所收获。 [源代码下载](http://files.cnblogs.com/jv9/SilverlightValidationDemo.rar) 欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)
';