SilverLight学习笔记--实际应用(一)(6):手把手建立一个Silverlight应用程序之创建数据校验类3

   前面我们讨论了关于如何在客户端进行同步数据校验以及如何在服务器端进行异步数据校验(其中包括如何创建一个等待异步数据校验的信息提示界面)。它们有两个共同点,那就是
  1、校验操作是在Person类定义中进行的
  2、针对单个绑定属性的校验,没有对校验结果进行集中管理
   在这里,我们继续完善我们的数据校验功能。我们需要达到的目标是:

  1、把校验工作从Person类中分离出来,打包进一个独立的类(校验类)中进行。也即:类定义和类校验分属两个不同的实体。
  
2、实现针对整个类对象的整体校验并对各属性的校验结果进行管理。

 一、创建一个独立的校验类
  我们将示范如何创建和使用一个独立的校验类。
 1、在SLApplicationDataTest项目中新添加一个类,此类专门负责针对Person类数据的校验工作,将此类命名为PersonValidator.cs。
代码如下:

 

 using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SLApplicationDataTest.SexServiceReference; //因为要使用WCF服务
using System.Windows.Browser; //因为要用到HtmlPage.Window.Alert
using System.ComponentModel; //因为要用到INotifyPropertyChanged


namespace SLApplicationDataTest
{
    
public class PersonValidator
    
{
        

    }

}



   分析代码我们可以看到:
   i、此类定义的每个属性都对应于Person类的相关属性,只不过在这里,由于它是校验类,所以它的每个属性都为Bool类型,以表示Person类的对应属性的数据校验是true还是false。如果结果为False,则表示校验正常。否则为true。
   ii、PersonValidator类的构造函数需要传入Person类对象实例,从而把Person类对象和PersonValidator类之间关联起来,也即:每个PersonValidator类对象负责校验与之对应的Person类实例对象数据。
   iii、PersonValidator类的每个属性都有与之对应的Validate方法如:ValidateAge(),ValidateName(),ValidateSex(),这些校验方法直接返回和影响对应的PersonValidator属性(Bool类型)
   iv、创建了传入参数Person类对象实例的PropertyChanged事件处理函数。当外部的Person类对象相关属性值发生变化时,此变化就会激活PersonValidator类对象内部对应的PropertyChanged事件处理,则它来接管对应属性值的校验工作,并把校验结果直接反应到PersonValidator类的对应属性值上。例如:当某个Person类对象的Age属性发生了变化,由于此Person类对象是做为参数传递给某个PersonValidator类对象的构造函数的,所以它就会触发PersonValidator类对象中的Person类传参的PropertyChanged事件,在此事件中遍历找到是年龄属性在变化,于是调用对应的ValidateAge()方法进行校验,如果校验通过则PersonValidator类对象的InvalidAge属性为False。

 2、修改Person类定义代码,建立Person类与PersonValidator校验类的关联,代码如下:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel; //因为要用到INotifyPropertyChanged接口
using SLApplicationDataTest.SexServiceReference; //因为要使用WCF服务
using System.Windows.Browser; //因为要使用HtmlPage.Window.Alert


namespace SLApplicationDataTest
{
    
public class Person : INotifyPropertyChanged
    
{
        
private  PersonValidator _personValidator; //定义一个PersonValidator类对象

        
private string _name;
        
private string _sex;
        
private int _age;
        
private string _address;

        
Person类对象的构造函数

        
Person类对象的属性

        
INotifyPropertyChanged 接口实现

    }

}

 我们做了如下修改
  i、去掉了相关属性的校验代码段,因为在这里我们已经把相关校验工作分离到了PersonValidator类中,由PersonValidator类来完成对应属性的校验工作。
  ii、定义一个私有的PersonValidator类对象,并在Person类的构造函数中创建此PersonValidator类对象,创建的同时,把自己作为参数传递给PersonValidator类对象的构造函数,从而建立起了Person类对象和PersonValidator类对象之间的紧密关联。
  iii、新添加了一个名为Validator的属性,通过此属性把与Person类对象关联的PersonValidator类对象实例公开出来以便于使用(绑定和读取校验结果值).

 3、应用重构的数据校验类PersonValidator
  我们在绑定Person类对象的数据时,可以通过Person类对象的Validator属性来得到与其对应的PersonValidator类对象实例,并可以读取它的相关属性。因为PersonValidator类的属性都是Bool类型,它表示对应的Person类属性的数据校验是否通过。因此,如何使用它?
   在这里,我们想通过改变对应数据的背景颜色来反应PersonValidator类对应属性的校验结果值。那么,我们的问题是:如果把不同的bool结果反应成对应的背景颜色值并在前端进行表现。所以,我们要用到IValueConverter接口,使用它,我们可以顺利的完成数据绑定过程中的表现类型的转换。IValueConverter使用的相关文章见另一篇(SilverLight学习笔记--关于使用IValueConvert对绑定数据的格式化操作 )。
   在改变绑定数据的背景颜色的同时,我们还想显示不同的错误提示信息。也即根据校验结果的不同,绑定不同的信息提示。
   总之,对PersonValidator类校验的结果,我们要
  (1)、改变绑定数据的背景颜色
  (2)、改变绑定数据栏的提示信息
  它们都需要用到IValueConverter接口。
 为此,我们创建两个类
  InvalidToBrushConverter.cs类定义代码如下 :
 

 

Code

  ErrMsgConverter.cs类定义代码如下:


Code
至此,应用程序如下图:

                        

 接下来的工作就是在修改我们的用户界面代码Page.xaml代码如下:
 

Code

 在界面方面,我们做如下工作:
 1、引入我们定义的类对象,引入代码:

    xmlns:myscreen="clr-namespace:SLApplicationDataTest"
    xmlns:myconvert
="clr-namespace:SLApplicationDataTest"

 2、添加控件级资源

      <UserControl.Resources>
        
<myconvert:InvalidToBrushConverter x:Key="myBrushConvert"/>   
        
<myconvert:ErrMsgConverter x:Key="myErrMsgConvert"/>
     
</UserControl.Resources>

 3、校验结果的数据绑定(颜色表现的绑定Background,与提示信息的绑定 ToolTipService.ToolTip)

 <Border Background="{Binding Validator.InvalidName, Converter={StaticResource myBrushConvert }}"
                                       ToolTipService.ToolTip
="{Binding Validator.InvalidName, Converter={StaticResource myErrMsgConvert},,ConverterParameter=Name}">                                   
                                   
<TextBlock  Text="{Binding Name}" ></TextBlock>
                                
</Border>

二、对上述创建的校验类进一步完善,用数据字典管理校验结果
  接下来,我们引入Dictionary,由它来集中管理各属性的校验结果。当有某个字段数据校验没有通过,则由PersonValidator类向Dictionary中添加字段名以及出错提示信息。如果此校验错误得到了更正,则由PersonValidator类负责从Dictionary中移除对应的键值对,如果Dictionary中为空,则表示某个Person类对象各属性值的校验都正确。
  下面进行我们的修改。
 1、PersonValidator类全部代码如下:

 

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SLApplicationDataTest.SexServiceReference; //因为要使用WCF服务
using System.Windows.Browser; //因为要用到HtmlPage.Window.Alert
using System.ComponentModel; //因为要用到INotifyPropertyChanged
using System.Collections.Generic;


namespace SLApplicationDataTest
{
    
public class PersonValidator
    
{
        
相关常量定义

        
年龄属性及年龄校验

        
姓名属性及姓名校验

        
性别属性及性别校验

        
整体校验属性


        Person _data; 
//定义一个Person类对象(此对象将会被关联到需要校验的实际Person对象)

        
PersonValidator构造函数(把要校验的Person类对象做为参数传递给PersonValidator类的构造函数以建立相互之间的关联)

        
PersonValidator类的Validate方法

        
INotifyPropertyChanged Members


        
获取对应字段的校验出错提示信息


        
error Dictionary 字典管理
    }

}

 代码说明:  我们对此类进行了大量修改,引入了Dictionary,创建了针对Dictionary进行管理的函数(键值对的添加、更新与删除操作),还对各属性定义进行了修改,
  属性值的变化直接反映到Dictionary记录内容的变量(取代了存放各属性值的私有变量)。

 2、Person类全部代码如下:

 

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel; //因为要用到INotifyPropertyChanged接口
using SLApplicationDataTest.SexServiceReference; //因为要使用WCF服务
using System.Windows.Browser; //因为要使用HtmlPage.Window.Alert


namespace SLApplicationDataTest
{
    
public class Person : INotifyPropertyChanged
    
{
        
private  PersonValidator _personValidator; //定义一个PersonValidator类对象

        
private string _name;
        
private string _sex;
        
private int _age;
        
private string _address;

        
Person类对象的构造函数

        
Person类对象的属性

        
INotifyPropertyChanged 接口实现

        
RaisePropertyChanged方法



    }

}

 代码说明:主要加入了RaisePropertyChanged方法,此方法主要用在PersonValidator类中的Person类对象整体校验属性功能中。

 3、ErrMsgConverter类全部代码如下:

 

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;//因为要用到IValueConverter接口

namespace SLApplicationDataTest
{
    
public class ErrMsgConverter : IValueConverter
    
{
        
IValueConverter Members
    }

}

 代码说明:我们在这时主要对返回出错信息的方法进行了修改,出错信息的提取主要来自PersonValidator类对象中的Dictionary记录内容。

 4、界面内容的修改,Page.xaml全部代码如下:
 

Code

 代码说明:
  i、首先是数据绑定的内容发生了变化,例如:
 ToolTipService.ToolTip="{Binding Path=Validator, Converter={StaticResource myErrMsgConvert}, ConverterParameter=Age}"

  ii、校验事件的处理移交到DataGrid层面。 BindingValidationError="dgPeople_BindingValidationError",其后台代码如下:

Code

Page.xaml.cs全部代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser; //因为要使用HtmlPage.Window.Alert(message));


namespace SLApplicationDataTest
{
    
public partial class Page : UserControl
    
{
        People mypeople;
        
public Page()
        
{
            InitializeComponent();

            
this.addButton.Click += new RoutedEventHandler(addButton_Click);
            
this.deleteButton.Click += new RoutedEventHandler(deleteButton_Click);
            
this.dgPeople.KeyDown += new KeyEventHandler(peopleDataGrid_KeyDown);



            Loaded 
+= new RoutedEventHandler(Page_Loaded);
        }


        
private void Page_Loaded(object sender, RoutedEventArgs e)
        
{
            
取得数据源数据并绑定到DataGrid控件上

        }


        
通过按钮添加新记录行

        
通过按钮删除记录

        
删除记录子程序

        
处理键盘响应事件


        
校验错误处理程序

        
打开与关闭“等待校验窗口”

        
private void dgPeople_BindingValidationError(object sender, ValidationErrorEventArgs e)
        
{
            
if (e.Action == ValidationErrorEventAction.Added)
            
{
                Person person 
= ((Control)e.OriginalSource).DataContext as Person;
                
if (null != person && null != ((Control)e.OriginalSource).Tag)
                
{
                    person.Validator.RegisterError(((Control)e.OriginalSource).Tag.ToString(), e.Error.Exception.Message);
                }

                
//((Control)e.Source).Background = new SolidColorBrush(Colors.Red);      
                
//((Control)e.Source).SetValue(ToolTipService.ToolTipProperty, e.Error.Exception.Message);    
            }

            
else if (e.Action == ValidationErrorEventAction.Removed)
            
{
                Person person 
= ((Control)e.OriginalSource).DataContext as Person;
                
if (null != person && null != ((Control)e.OriginalSource).Tag)
                
{
                    person.Validator.ClearError(((Control)e.OriginalSource).Tag.ToString());
                }

                
//((Control)e.Source).Background = new SolidColorBrush(Colors.White);    
                
//((Control)e.Source).SetValue(ToolTipService.ToolTipProperty, null);
            }


        }

    }

}

生成项目并F5运行,效果如下 :
 

 

前往:Silverlight学习笔记清单
本文程序在Silverlight2.0和VS2008环境中调试通过。本文参照了部分网络资料,希望能够抛砖引玉,大家共同学习。
(转载本文请注明出处)

posted @ 2009-09-11 09:22  wsdj  阅读(830)  评论(2编辑  收藏  举报