WPF入门(五):简单绑定 - 用户输入合法性验证

在我们绑定完数据后,在用户输入数据后,还需要进行用户输入合法性验证,比如需要判断 必填项,email地址输入格式,日期格式是否正确等。

wpf为我们提供了一种验证用户合法行的方式。依赖于绑定。在将实体数据绑定到视图后,如果用户输入的视图改变,则同时通知实体的属性值改变。先看代码:

 

1. 构建一个要绑定到界面的实体。该实体实现了IDataErrorInfo接口,在接口里写了验证规则。

ExpandedBlockStart.gif 代码
  // 实体 实现 IDataErrorInfo接口,并在 this[]索引器里定制自己的验证规则
     class  Person : IDataErrorInfo
    {
        
public   string  Name {  get set ; }
        
public   int  Age {  get set ; }

        
#region  IDataErrorInfo 成员

        
string  _err;
        
public   string  Error
        {
            
get  {  return  _err; }
        }

        
// 定制验证规则
         public   string   this [ string  columnName]
        {
            
get
            {
                
string  err  =   "" ;
                
switch  (columnName)
                {
                    
case   " Name " :
                        
if  ( string .IsNullOrEmpty( this .Name))
                        {
                            err 
=   " 名称不能为空 " ;
                        }
                        
else
                        {
                            
if  ( this .Name.Length  >   8 )
                            {
                                err 
=   " 名称太长了,不能大于8个字符 " ;
                            }
                        }
                        
break ;
                    
case   " Age " :

                        
if  ( this .Age  <   0   ||   this .Age  >   200 )
                        {
                            err 
=   " 年龄不合法 " ;
                        }
                        
break ;
                }
                _err 
=  err;
                
return  _err;
            }
        }

        
#endregion
    }

 

 

2.页面:

ExpandedBlockStart.gif 代码
 1  < Window x:Class = " WpfApplication3.Window1 "
 2      xmlns = " http://schemas.microsoft.com/winfx/2006/xaml/presentation "
 3      xmlns:x = " http://schemas.microsoft.com/winfx/2006/xaml "
 4           xmlns:local  = " clr-namespace:WpfApplication3 "
 5      Title = " Window1 "  Height = " 298 "  Width = " 681 "  Loaded = " Window_Loaded " >
 6 
 7       < Grid Name = " grid1 " >
 8           < TextBlock Margin = " 25,29,0,0 "  Name = " textBlock1 "  Height = " 21 "  VerticalAlignment = " Top "  HorizontalAlignment = " Left "  Width = " 38 " >
 9              Name:
10           </ TextBlock >
11           < TextBox HorizontalAlignment = " Left "  Margin = " 83,29,0,0 "  Name = " textBlock2 "  VerticalAlignment = " Top "  Width = " 120 "   >
12               < TextBox.Text >
13                   <!--  启动Binding的绑定方式1  -->
14                   < Binding Path = " Name "   UpdateSourceTrigger = " PropertyChanged "
15                           ValidatesOnDataErrors = " True "   />
16               </ TextBox.Text >
17           </ TextBox >
18           < TextBlock Text = " Age: "  Height = " 21 "  HorizontalAlignment = " Left "  Margin = " 25,68,0,0 "  Name = " textBlock3 "  VerticalAlignment = " Top "  Width = " 38 "   />
19           < TextBox  Height = " 23 "  HorizontalAlignment = " Left "  Margin = " 83,66,0,0 "  Name = " textBox1 "  VerticalAlignment = " Top "  Width = " 120 "   >
20               < TextBox.Text >
21                   <!--  启动Binding的绑定方式2  -->
22                   < Binding Path = " Age "  UpdateSourceTrigger = " PropertyChanged " >
23                       < Binding.ValidationRules >
24                           < DataErrorValidationRule  />
25                           < ExceptionValidationRule ></ ExceptionValidationRule >
26                       </ Binding.ValidationRules >
27                   </ Binding >
28               </ TextBox.Text >
29           </ TextBox >
30       </ Grid >
31  </ Window >
32 

 

页面的后置代码:

 

ExpandedBlockStart.gif 代码
 1       ///   <summary>
 2       ///  Window1.xaml 的交互逻辑
 3       ///   </summary>
 4       public   partial   class  Window1 : Window
 5      {
 6           public  Window1()
 7          {
 8              InitializeComponent();
 9          }
10 
11           private   void  Window_Loaded( object  sender, RoutedEventArgs e)
12          {
13              grid1.DataContext  =  GetPersonFromDatabase();
14          }
15 
16           private  Person GetPersonFromDatabase()
17          {
18               // 从数据库获得数据对象 <演示>
19               return   new  Person() { Name  =   " join " , Age  =   30  };
20          }
21      }

按F5运行后,尝试输入写不合法数据。可以看到Textbox的边框变成红色。这是一种默认的提示错误的风格方式,我们还可以对这个提示风格进行自定义。

 

注意Binding的下面两个属性:

ValidatesOnDataErrors 获取或设置一个值,该值指示是否包含 DataErrorValidationRule

ValidationRules 获取用于检查用户输入有效性的规则集合。

也就是说当我们设置了 Binding的ValidatesOnDataErrors="True" 时。WPF框架在构造Binding对象时,会自动的添加一个默认的DataErrorValidationRuleValidationRules 属性值(验证规则列表)内。或者我们直接在ValidationRules 里添加我们需要的规则,比如下面是添加了两个规则:

<Binding.ValidationRules>
                       <DataErrorValidationRule />
                       <ExceptionValidationRule></ExceptionValidationRule>
</Binding.ValidationRules>

这样的写法很有意思,貌似IOC的方式配置文件,比如spring.Net的配置文件,这样的声明ValidationRules的包含的规则。当WPF框架创建对象时自动的完成规则操作,并判断ValidationRules内的规则数量,如果多于0个,就遍历所有的规则集合,如果集合中包含了DataErrorValidationRule 并且实体类显示了IDataErrorInfo
接口,就调用 实体内包含的 验证规则。

ExceptionValidationRule 类是一个内置的规则,它检查在绑定源属性更新过程中引发的异常。这里验证了Age的用户输入不可为空,当为空时,转型成int(Age是int类型)时就会出错。

 

通过创建一个从 ValidationRule 派生的类,可以创建自定义规则。下面我尝试自定义验证规则。

MSDN里对ValidateionRule的描述如下:

在使用 WPF 数据绑定模型时,可将 ValidationRules 与绑定对象关联。若要创建自定义规则,请创建此类的子类并实现 Validate 方法。也可选择使用内置的 ExceptionValidationRule(该类捕获在源更新期间引发的异常)或 DataErrorValidationRule(该类检查源对象的 实现所引发的错误)。

绑定引擎在每次将输入值(即绑定目标属性值)传给绑定源属性时将检查与绑定关联的每一个 ValidationRule

我们写一个类继承自ValidationRule,代码如下:

ExpandedBlockStart.gif代码

 1    class  AgeValidationRule : ValidationRule
 2      {
 3           // 验证规则
 4           public   override  ValidationResult Validate( object  value, System.Globalization.CultureInfo cultureInfo)
 5          {
 6               if  (value  ==   null )
 7              {
 8                   return   new  ValidationResult( false " 年龄不能为空 " );
 9              }
10               int  valNew  =   0 ;
11               if  ( ! int .TryParse(value.ToString(),  out  valNew))
12              {
13                   return   new  ValidationResult( false , value  +   " 不是一个数字类型 " );
14              }
15               else
16              {
17                   if  (valNew  <   0   ||  valNew  >   200 )
18                  {
19                       return   new  ValidationResult( false " 年龄必须在0和200之间 " );
20                  }
21              }
22               return  ValidationResult.ValidResult;
23          }

实体的代码:

 

1       // 实体 
       class  Person 
3      {
4           public   string  Name {  get set ; }
5           public   int  Age {  get set ; }
6 
7      }

 

 

页面xaml代码如下,而后置代码不变。

ExpandedBlockStart.gif 代码
 1  < Window x:Class = " WpfApplication3.Window1 "
 2      xmlns = " http://schemas.microsoft.com/winfx/2006/xaml/presentation "
 3      xmlns:x = " http://schemas.microsoft.com/winfx/2006/xaml "
 4           xmlns:local  = " clr-namespace:WpfApplication3 "
 5      Title = " Window1 "  Height = " 298 "  Width = " 681 "  Loaded = " Window_Loaded " >
 6 
 7       < Grid Name = " grid1 " >
 8           < TextBlock Margin = " 25,29,0,0 "  Name = " textBlock1 "  Height = " 21 "  VerticalAlignment = " Top "  HorizontalAlignment = " Left "  Width = " 38 " >
 9              Name:
10           </ TextBlock >
11           < TextBox HorizontalAlignment = " Left "  Margin = " 83,29,0,0 "  Name = " textBlock2 "  VerticalAlignment = " Top "  Width = " 120 "   >
12               < TextBox.Text >
13                   <!--  启动Binding的绑定方式1  -->
14                   < Binding Path = " Name "   UpdateSourceTrigger = " PropertyChanged "
15                           ValidatesOnDataErrors = " True "   />
16               </ TextBox.Text >
17           </ TextBox >
18           < TextBlock Text = " Age: "  Height = " 21 "  HorizontalAlignment = " Left "  Margin = " 25,68,0,0 "  Name = " textBlock3 "  VerticalAlignment = " Top "  Width = " 38 "   />
19           < TextBox  Height = " 23 "  HorizontalAlignment = " Left "  Margin = " 83,66,0,0 "  Name = " textBox1 "  VerticalAlignment = " Top "  Width = " 120 "   >
20               < TextBox.Text >
21                   <!--  启动Binding的绑定方式2  -->
22                   < Binding Path = " Age "  UpdateSourceTrigger = " PropertyChanged " >
23                       < Binding.ValidationRules >
24                           <!--  我们自定义的验证规则  -->
25                           < local:AgeValidationRule  />
26                           < ExceptionValidationRule ></ ExceptionValidationRule >
27                       </ Binding.ValidationRules >
28                   </ Binding >
29               </ TextBox.Text >
30           </ TextBox >
31       </ Grid >
32  </ Window >
33 

 

F5运行。是不是一样呢。我个人不推荐第一种方法。当实体实现了IDataErrorInfo,并在实体的代码里写验证规则时,会把代码搞的非常混杂。网上有推荐利用Attribute的进行验证的,但是好像还要让实体继承一个基类。我更喜欢让实体model干干净净。

 

下面我们看看如何更改在验证失败时的提示风格。

 

ExpandedBlockStart.gif 代码
< Window x:Class = " WpfApplication3.Window1 "
    xmlns
= " http://schemas.microsoft.com/winfx/2006/xaml/presentation "
    xmlns:x
= " http://schemas.microsoft.com/winfx/2006/xaml "
         xmlns:local 
= " clr-namespace:WpfApplication3 "
    Title
= " Window1 "  Height = " 298 "  Width = " 681 "  Loaded = " Window_Loaded " >

    
< Grid Name = " grid1 " >
        
< TextBlock Margin = " 25,29,0,0 "  Name = " textBlock1 "  Height = " 21 "  VerticalAlignment = " Top "  HorizontalAlignment = " Left "  Width = " 38 " >
            Name:
        
</ TextBlock >
        
< TextBox HorizontalAlignment = " Left "  Margin = " 83,29,0,0 "  Name = " textBlock2 "  VerticalAlignment = " Top "  Width = " 120 "   >
            
< TextBox.Text >
                
<!--  启动Binding的绑定方式1  -->
                
< Binding Path = " Name "   UpdateSourceTrigger = " PropertyChanged "
                         ValidatesOnDataErrors
= " True "   />
            
</ TextBox.Text >

        
</ TextBox >
        
< TextBlock Text = " Age: "  Height = " 21 "  HorizontalAlignment = " Left "  Margin = " 25,68,0,0 "  Name = " textBlock3 "  VerticalAlignment = " Top "  Width = " 38 "   />
        
< TextBox  Height = " 23 "  HorizontalAlignment = " Left "  Margin = " 83,66,0,0 "  Name = " textBox1 "  VerticalAlignment = " Top "  Width = " 120 "   >
            
< TextBox.Text >
                
<!--  启动Binding的绑定方式2  -->
                
< Binding Path = " Age "  UpdateSourceTrigger = " PropertyChanged " >
                    
< Binding.ValidationRules >
                        
<!--  我们自定义的验证规则  -->
                        
< local:AgeValidationRule  />
                        
< ExceptionValidationRule ></ ExceptionValidationRule >
                    
</ Binding.ValidationRules >
                
</ Binding >
            
</ TextBox.Text >
            
< Validation.ErrorTemplate >
                
< ControlTemplate >
                    
<!--  ControlTemplate要求只能有一个子级,所以加个容器控件DockPanel  -->
                    
< DockPanel >
                        
<!--  AdornedElementPlaceholder就是要验证的控件本身,本例里是个TextBox  -->
                        
< AdornedElementPlaceholder  />
                        
< TextBlock Foreground = " Red "  FontSize = " 20 "  Text = " * "   />
                    
</ DockPanel >
                
</ ControlTemplate >
            
</ Validation.ErrorTemplate >
        
</ TextBox >
    
</ Grid >
</ Window >

 

我们注意到Textbox.Validation属性的ErrorTemplate是发生错误时使用的模板,我们重新new了一个ControlTemplate来代替这个模板。在这个模板里我们定义了一个DockPanel作为容器控件,使用 占位标记AdornedElementPlaceholder 标记了TextBox的位置,并在它后面添加两个 字符"*"号。这可能有点难以理解。换个说法是,每个TextBox都有个Validation属性,Validation包含了一些和验证相关的像,包含有个当验证失败时的显示模板。而我们重新定义了个显示模板。这个模板里有个占位符,占位符表示TextBox本身,我们在这个模板的占位符后面添加一些字符 红色的"*" 号。那么当TextBox在执行时,如果失败,就会把 错误模板 显示出来,并在 占位符位置 显示自己。

 

我们换个另外的方式来改变视图效果,使用style 方式。

在窗体资源里添加一个style,style这个东西呢,类似web开发中的css。他有个属性TargetType 指示了这个样式的作用域。本例中指示了 所有的TextBox,style的强大之处还有个Triggers就是触发器。本例中触发器指向一个属性Validation.HasError属性,当这属性的值为"True"时,触发Trigger包含的样式。当不等于"True"时,自动改回原来的样式。很强大吧。Setter元素提供了设置目标对象属性的方法,我们直接更改了Textbox.ToolTop属性,那么当鼠标移动到控件上时,就会显示发生错误的原因。

ExpandedBlockStart.gif 代码
 1       < Window.Resources >
 2           < Style TargetType = " TextBox " >
 3               < Style.Triggers >
 4                   < Trigger Property = " Validation.HasError "  Value = " True " >
 5                       < Setter Property = " Background "  Value = " #DDD "   />
 6                       < Setter Property = " Foreground "  Value = " Red "   />
 7                       < Setter Property = " ToolTip "   
 8                             Value = " {Binding RelativeSource={RelativeSource Self},Path=(Validation.Errors)[0].ErrorContent} " />
 9                   </ Trigger >
10               </ Style.Triggers >
11           </ Style >
12       </ Window.Resources >

 

这句<Setter Property="ToolTip"  
                            Value="{Binding RelativeSource={RelativeSource Self},Path=(Validation.Errors)[0].ErrorContent}"/>

完成了获得关联数据源,并绑定错误提示的操作。

 下载代码

本节完。

待续ing...


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值