Silverlight3系列(六)数据验证 Data Validation

  本篇我们讨论SL3中的数据验证相关知识。

  数据验证只会发生双向绑定的情况下,因为实体类需要实现INotifyPropertyChanged接口。在SL中数据绑定的时候如果遇到没有验证的数据,通常会忽略它。下面的表中,列出在双向绑定的时候,三种类型的错误:

  1、不正确的数据。例如:本来是应该数字类型的,不应该输入字符或者其他字符,同时,也不能超出最大值。

  2、对象属性的set异常。例如:在属性Id的set中有一个判断,如果有问题就抛出异常。

  3、只读属性,你不能进行赋值操作。

  如果是上面的错误,你不能忽略他们,因为sl的数据绑定不会给你任何可视化的提示信息。不正确的值保留在绑定控件中,但是没有应用到绑定对象中。

  避免这个问题的好办法就是及时的提醒用户,输入有问题。最容易的途径包括:使用绑定对象的两个属性,ValidatesOnExceptions、NotifyOnValidationError,这些都会激活sl的错误提醒事件。

  1、ValidatesOnException

  ValidatesOnException是实现其他验证的第一步。在你设置ValidatesOnException=true之后,数据绑定将会对任何错误做出响应,不管它是出现在类型转换还是属性的setter。但是,当设置ValidatesOnException=false(默认为false)之后,数据绑定不会提示任何错误。绑定对象没有被更新,错误的值保留在了绑定控件中。

  下面是绑定控件的设置例子

  

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> < TextBox  x:Name ="customerId"  Grid.Column ="1"  Grid.Row ="1"  Text =" {Binding  CustomerId, Mode=TwoWay, ValidatesOnExceptions=true} " ></ TextBox >
  

 

  这样设置之后,你的控件在双向绑定之后可以进行捕获和显示错误的能力,具有这种能力的控件包括。

  •   TextBox
  •   PasswordBox
  •   CheckBox
  •   RadioButton
  •   ListBox
  •   ComboBox

  知识点:验证状态ValidationState包括三种:Valid、InvalidUnfocused、InvalidFocused。

  这里我们再一个属性的setter中添加验证,

  

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->     public   virtual   int  CustomerId
        {
            
get  {  return   this ._intCustomerId; }
            
set
            {
                
int  result;
                
if  (Int32.TryParse(value.ToString(),  out  result)  ==   false )
                    
throw   new  ArgumentException( " 必须是数字 " );
                
this ._intCustomerId  =  result;
                OnPropertyChanged(
" CustomerId " );
            }
        }

 

  现在如果用户输入一个非数字的用户Id,setter将会捕获这个异常,因为你设置了ValidatesOnExceptions=true,数据绑定系统将会捕获这个异常,将控件的ValidationState从Valid变成InvalidFocused(如果控件当前获得焦点)或者InvalidUnfocused(如果当前控件失去焦点)。

  Silverlight3系列(六)数据验证 Data Validation

  如上图所示,用户信息是从数据库中读取出来的,我将显示框都换成了输入框,这时候我在123后面添加df,然后焦点从id输入框移出之后,id框外圈会变成红色,这时候ValidationState从Valid变成InvalidUnfocused,因为失去焦点。

 

  这时候当你的焦点回到id框之后,会弹出后面的红色提示信息“输入格式不正确”,也就是你在setter中抛出的异常,这时候ValidationState从Valid变成InvalidFocused,因为又获得焦点。

  Silverlight3系列(六)数据验证 Data Validation

  知识点:如果上面的提示信息太长,会被截断显示,右面显示不下,会显示在左面。

  这时候,你发现错误提示很容易也很有用。因为控件使用可视化的错误提示,你简单到只需要考虑显示的信息就可以了。

  2、NotifyOnValidationError

  在设置ValidatesOnException=true之后,你还是可以选择使用NotifyOnValidationError的。如果你这么做,数据绑定系统会在发现错误之后激活BindingValidationError事件。

  

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->   < TextBox  x:Name ="TxtCustomerId"  Grid.Column ="1"  Grid.Row ="0"  
                         Text
=" {Binding CustomerId, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationErro=true} " />

 

  BindingValidationError事件会向上抛出,意味着你可以在发生的地方(textbox)捕获,也可以在上一级(包含textbox的grid)进行捕获。发生错误的时候,你可以在不同的级别写代码来处理错误。

  

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->   < Grid  x:Name ="LayoutRoot"  Background ="White"  BindingValidationError ="LayoutRoot_BindingValidationError" >

 

  上面就是在textbox所在的grid中抛出错误,你可以写代码来进行处理,显示错误信息之类的。但是一般都是改变焦点,重置错误的值,提供一些详细信息,下面的代码提示错误信息,显示了旧值,并且将焦点返回到textbox控件。

Silverlight3系列(六)数据验证 Data Validation

  

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> < Grid  x:Name ="LayoutRoot"  Background ="White"  BindingValidationError ="LayoutRoot_BindingValidationError" >
                
< Grid.ColumnDefinitions >
                    
< ColumnDefinition />
                    
< ColumnDefinition />
                
</ Grid.ColumnDefinitions >
                
< Grid.RowDefinitions >
                    
< RowDefinition  />
                    
< RowDefinition  Height ="20"   />
                    
< RowDefinition  Height ="20" />
                    
< RowDefinition  Height ="20" />
                    
< RowDefinition  Height ="20" />
                    
< RowDefinition  Height ="20" />
                    
< RowDefinition  Height ="20" />
                
</ Grid.RowDefinitions >
                
< TextBlock  x:Name ="LblCustomerId"  Grid.Column ="0"  Grid.Row ="0"  Text ="Customer Id" />
                
< StackPanel  Grid.Row ="0"  Grid.Column ="1"  Orientation ="Vertical" >
                    
< TextBox  x:Name ="TxtCustomerId"   Height ="25"
                         Text
=" {Binding CustomerId, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=true} " />
                
< TextBlock  x:Name ="lblErrorMessage"  Height ="30" ></ TextBlock >
                
</ StackPanel >
                
                
< TextBlock  x:Name ="LblCustomerCode"  Grid.Column ="0"  Grid.Row ="1"  Text ="Customer Code" />
                
< TextBox  x:Name ="TxtCustomerCode"  Grid.Column ="1"  Grid.Row ="1"  Text =" {Binding CustomerCode, Mode=TwoWay, ValidatesOnExceptions=True} " />
                
< TextBlock  x:Name ="LblCustomerName"  Grid.Column ="0"  Grid.Row ="2"  Text ="用户名称" />
                
< TextBox  x:Name ="TxtCustomerName"  Grid.Column ="1"  Grid.Row ="2"  Text =" {Binding CustomerName, Mode=TwoWay, ValidatesOnExceptions=True} " />
                
< TextBlock  x:Name ="LblCustomerType"  Grid.Column ="0"  Grid.Row ="3"  Text ="用户类型" />
                
< TextBox  x:Name ="TxtCustomerType"  Grid.Column ="1"  Grid.Row ="3"  Text =" {Binding CustomerTypeName, Mode=TwoWay, ValidatesOnExceptions=True} " />

            
</ Grid >

 

 

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->   private   void  LayoutRoot_BindingValidationError( object  sender, ValidationErrorEventArgs e)
        {
            lblErrorMessage.Text 
=  e.Error.Exception.Message;
            lblErrorMessage.Text 
+=   " \nThe stored value is still:  "   +  (((Customer)LayoutRoot.DataContext).CustomerId.ToString());

            TxtCustomerId.Focus();
        }

 

  BindingValidationError事件只会在控件失去焦点才会被激活,如果你想马上产生效果,你可以使用BindingExpression.UpdateSource();方法来激活事件。

  3、Validation Class 验证类

  如果你不想用BindingValidationError来发现错误信息,你可以使用验证类Validation的静态方法随时检查绑定控件的错误信息。如果控件验证失败,Validation.GetHasErrors()方法返回true,ValidationGetErrors()方法返回一个只读的错误集合。

  这些方法增加了你的灵活性,例如你可以检查Validation.GetHasErrors()方法,如果发现非法数据,可以禁止用户进行下一步操作。

  你还可以使用ValidationGetErrors()将所有的错误都返回,显示在一个地方。

  4、输入验证

  上面提供的都是显示数据之后,你修改的话,会产生验证,下面我们讲一个输入验证的例子。其实就是一个小技巧,输入的时候我们还没有绑定数据的话,就不会产生验证的,因为验证只发生在双向绑定的情况下。

  其他我们可以在打开输入页面之后,就绑定一个数据,就是一个空数据,一个刚刚初始化的对象就可以了。

  后面的就和前面的一样了。

  效果图,输入错误

  Silverlight3系列(六)数据验证 Data Validation

  效果图,输入正确

  

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->   < Grid x:Name = " AddCustomer "  Background = " White "  Grid.Column = " 0 "  Grid.ColumnSpan = " 2 "  Grid.Row = " 5 "  Height = " 97 " >
                
< Grid.ColumnDefinitions  >
                    
< ColumnDefinition Width = " 0.5* " ></ ColumnDefinition >
                    
< ColumnDefinition Width = " 0.5* " ></ ColumnDefinition >
                
</ Grid.ColumnDefinitions >
                
< Grid.RowDefinitions  >
                    
< RowDefinition Height = " 0.247* "   ></ RowDefinition >
                    
< RowDefinition  ></ RowDefinition >
                    
< RowDefinition Height = " 0.247* "   ></ RowDefinition >
                    
< RowDefinition Height = " 0.258* "   ></ RowDefinition >
                    
< RowDefinition Height = " 0.258* "   ></ RowDefinition >
                
</ Grid.RowDefinitions >
                
< TextBlock Text = " 用户类型 "  Grid.Column = " 0 "  Grid.Row = " 0 " ></ TextBlock >
                
< ComboBox x:Name = " cmbCustomerType "  Grid.Column = " 1 "  Grid.Row = " 0 " ></ ComboBox >
                
< TextBlock Text = " 用户 Id "  Grid.Column = " 0 "  Grid.Row = " 1 " ></ TextBlock >
                
                
< StackPanel Grid.Row = " 1 "  Grid.Column = " 1 "  Orientation = " Vertical " >
                    
< TextBox x:Name = " customerId "  
                         Text
= " {Binding CustomerId, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=true} "
                         BindingValidationError
= " customerId_BindingValidationError "  LostFocus = " customerId_LostFocus " >

                    
</ TextBox >
                    
< TextBlock x:Name = " lblErrorMsg "  Height = " 30 " ></ TextBlock >
                
</ StackPanel >
                
< TextBlock Text = " Custoemr Code "  Grid.Column = " 0 "  Grid.Row = " 2 " ></ TextBlock >
                
< TextBox x:Name = " customerCode "  Grid.Column = " 1 "  Grid.Row = " 2 " ></ TextBox >
                
< TextBlock Text = " Customer Name "  Grid.Column = " 0 "  Grid.Row = " 3 " ></ TextBlock >
                
< TextBox x:Name = " customerName "  Grid.Column = " 1 "  Grid.Row = " 3 " ></ TextBox >
                
< Button x:Name = " btnOk "  Grid.Column = " 0 "  Grid.ColumnSpan = " 2 "  Grid.Row = " 4 "  Height = " 25 "  Content = " 添加用户Add Customer "
                        Click
= " btnOk_Click " ></ Button >
            
</ Grid >

 

  首先绑定一个空对象。

   AddCustomer.DataContext = new Customer();

  然后在验证代码事件中写代码。

   private void customerId_LostFocus(object sender, RoutedEventArgs e)
        {
            BindingExpression expression = customerId.GetBindingExpression(TextBox.TextProperty);
            expression.UpdateSource();
        }

 

  反正就是扩展一下思路就可以了。

  感谢大家的关注!!

  本系列的完整代码都可以从http://silverlightwcf.codeplex.com/下载。

  数据库的结构如下图:

 

  Silverlight3系列(六)数据验证 Data Validation

  

  Silverlight3系列(六)数据验证 Data Validation

你可能感兴趣的:(数据结构)