SilverLight学习笔记--实际应用(一)(7):手把手建立一个Silverlight应用程序之数据回滚...

  前面我们实现了如何添加,删除,修改以及校验数据记录,这里我们将使用一个接口IEditableObject来实现输入数据的回滚操作。
  我们在界面上输入的数据有校验错误或笔误时,我们希望回滚到原有的数据。这就要通过IEditableObject接口来实现。
  IEditableObject是数据绑定中用到的,主要是三个函数:BeginEdit()、CancelEdit()、EndEdit()。
  此类提供提交或回滚对用作数据源的对象所做更改的功能。
  该接口通常用于捕获 DataRow 的 BeginEdit,EndEdit 和 CancelEdit语义。这个接口支持撤销,当在DataGrid编辑一个实现了IEditableObject的 T 类型集合时,当前行默认的是编辑状态,当前焦点进入一个DataRow时,会触发 T中定义IEditableObject.BeginEdit函数,离开焦点时,会触发T中定义IEditableObject.EndEdit函数,按下ESC时,会触发CancelEdit函数。有了这个接口,我们就可以将一个类型的读写操作放到对象中,更符合面向对象的思想。同时,在一个界面中给DataGrid赋予不同的类型集合,集合中对象类型不同,都能实现属性的编辑,委托给合适的对象中的编辑函数,而不用对界面进行什么更改!

 1、加入并实现IEditableObject接口
  下面我们来实现程序的数据回滚操作,修改Person类,
  首先要继承接口,并加入下面的接口实现:

public   class  Person : INotifyPropertyChanged,IEditableObject 

ContractedBlock.gif ExpandedBlockStart.gif    IEditableObject 接口实现 #region IEditableObject 接口实现

        
private  Person _backup;  //用于保存编辑对象的原本
        private  bool _editing;   //处于编辑状态时为true,退出编辑状态时为false

        
void IEditableObject.BeginEdit()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (!_editing)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _editing 
= true;

                
//MemberwiseClone 方法在这里仅做演示,如果在实际应用时,应该用deep copy.
                _backup = this.MemberwiseClone() as Person;  //保存编辑前的内容
            }


        }


        
void IEditableObject.CancelEdit()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (_editing)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//取消当前编辑,恢复编辑前内容
                
//如果要取消当前编辑,请按下Esc键 

                Name 
= _backup.Name;
                Sex 
= _backup.Sex;
                Age 
= _backup.Age;
                Address 
= _backup.Address;
                _editing 
= false;
            }


        }


        
void IEditableObject.EndEdit()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (_editing)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _editing 
= false;
                
this._backup = null;//当前编辑生效
            }

        }


        
#endregion

  然后按下F5运行,依次修改某行的Name,Age,Sex或Address,然后再依次按下ESC健,可以看到,各记录的值依次回滚到修改前的数据(注意:当你的输入焦点退出当前行进入其它数据行时,前一行的回滚操作不再有效,因为当它退出焦点时,就提交了数据修改的生效)。 

 2、加入数据录入确定生效时的自定义事件
       借助IEditableObject,我们可以加入数据录入生效后的自定义事件。 也即:我们对数据进行了修改,如果用户cancel掉新的录入或修改,则不用激发我们的自定义事件,而如果用户确定录入生效,则激活我们的自定义事件。
   在Person类对象内加入以下自定义事件处理代码:
在EndEdit中激活ChangesCommitted 事件 

ContractedBlock.gif ExpandedBlockStart.gif Code
         void IEditableObject.EndEdit()
        {
            
if (_editing)
            {
                _editing 
= false;
                
this._backup = null;//当前编辑生效
                  OnChangesCommitted();  
                }

            }
        }

        
#endregion

ChangesCommitted 事件处理代码

      #region  ChangesCommitted 自定义事件处理过程
        
void  emptyPerson_ChangesCommitted( object  sender, EventArgs e)
        {
            emptyPerson.ChangesCommitted 
-=   new  EventHandler < EventArgs > (emptyPerson_ChangesCommitted);
            emptyPerson 
=   new  Person();
            MessageBox.Show(
" 本记录行更改已提交! " );
            emptyPerson.ChangesCommitted 
+=   new  EventHandler < EventArgs > (emptyPerson_ChangesCommitted);
            
base .InsertItem( this .Count, emptyPerson);
        }
        
#endregion

   我们定义了一个ChangesCommitted 事件,当用户结束editing时就会激活此事件(在EndEdit()代码段中激发此事件)
   接下来,我们需要修改People类,在那里加入我们对ChangesCommitted事件的具体处理方法。我们首先给People类新加入了一个方法AddNewPerson(),
此方法提供在当前的People记录中添加一个新的Person记录。代码如下: 

 

         public  People AddNewPerson(  )
        {
            emptyPerson 
=   new  Person();
            emptyPerson.ChangesCommitted 
+=   new  EventHandler < EventArgs > (emptyPerson_ChangesCommitted);
            
base .InsertItem( this .Count, emptyPerson);
            
return   this ;
        }

  
  接下来修改我们的Add按钮事件如下:

         #region  通过按钮添加新记录行
        
void  addButton_Click( object  sender, RoutedEventArgs e)
        {
           
//  mypeople.Add(new Person());
            mypeople  =  mypeople.AddNewPerson();
        }
        
#endregion

 
 按F5运行,按Add添加一新行,修改其中的记录,然后退出焦点,点击其它行,可以看到效果如下:

                         
    现在的问题是,即使我们输入的数据校验通不过,这个新的录入也会确定,并会自动在最后新添一行新记录,这不是我们想要的。所以,我们需要进一步完善,如果新的录入通不过校验,则不予确定,程序也不会在后面自动添加一个新的记录行。而如果校验通过,则程序会弹出提交修改信息,并自动在最后另起一新数据行。这个工作我们放在EndEdit中进行,如果录入的数据有效,则激活ChangesCommitted事件,PersonValidator 类已经有了Validate方法,我们将会使用它。
  修改Person类的EndEdit()如下: 

 

ContractedBlock.gif ExpandedBlockStart.gif Code
        void IEditableObject.EndEdit()
        {
            
if (_editing)
            {
                _editing 
= false;
                
this._backup = null;//当前编辑生效

 
                
//当用户结束Edit时,激发我们自定义的ChangesCommitted事件,在此事件中执行我们期望的其它处理工作

                
if (null != ChangesCommitted)
                {
                    _fireChangesCommited 
= true;

                    
//this.RootVisual就是Application.Current.RootVisual的值,也就是page control
                    
//所有的子控件都在RootVisual里面,可以通过  Page page = (Page)Application.Current.RootVisual得到这个Page对象。

                    Application.Current.RootVisual.Dispatcher.BeginInvoke(() 
=> _personValidator.Validate()); //调用 Validate方法进行校验

                    
//取消下面的OnChangesCommitted,也即不再在此处提交修改,推迟为由PersonValidator类中来做此项工作,如果校验都通过则提交否则不提交
                    
//  OnChangesCommitted();  
                }

            }
        }

  我们还另加入validator_Validated()来响应PersonValidator类校验通过的Validated事件。代码如下: 

 

         #region   PersonValidator 类校验通过事件响应
        
void  _validator_Validated( object  sender, EventArgs e)
        {
            
if  (_fireChangesCommited)
            {
                _fireChangesCommited 
=   false ;
                
if  (_personValidator.IsValid)
                {
                    Application.Current.RootVisual.Dispatcher.BeginInvoke(() 
=>  OnChangesCommitted());
                }
            }
        }
        
#endregion

         
  Person类全部代码如下:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
 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
ExpandedBlockStart.gifContractedBlock.gif
{
    
public class Person : INotifyPropertyChanged,IEditableObject 
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
private  PersonValidator _personValidator; //定义一个PersonValidator类对象

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

ContractedSubBlock.gifExpandedSubBlockStart.gif        
Person类对象的构造函数#region Person类对象的构造函数
ContractedSubBlock.gifExpandedSubBlockStart.gif        
构造函数一#region 构造函数一
        
public Person() 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//在新创建一个Person类对象的同时,创建一个PersonValidator对象,并将新创建的Person类对象传递给PersonValidator对象
            
//从而在Person类对象和PersonValidator之间建立了关联
            _personValidator = new PersonValidator(this);
            _personValidator.Validated 
+= new EventHandler<EventArgs>(_validator_Validated);

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
构造函数二#region 构造函数二
        
public Person(string NameStr, string SexStr, int AgeInt, string AddressStr):this()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
this._name = NameStr;
            
this._sex = SexStr;
            
this._age = AgeInt;
            
this._address = AddressStr;
        }

        
#endregion

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
Person类对象的属性#region Person类对象的属性

ContractedSubBlock.gifExpandedSubBlockStart.gif        
姓名属性#region 姓名属性
        
public string Name
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return _name; }
            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (value == _name) return;
                _name 
= value;
                OnPropertyChanged(
"Name");
            }

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
性别属性#region 性别属性
        
public string Sex
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return _sex; }
            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (value == _sex) return;
                _sex 
= value;
                OnPropertyChanged(
"Sex");
            }

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
年龄属性#region 年龄属性
        
public int Age
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return _age; }
            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (value == _age) return;

ContractedSubBlock.gifExpandedSubBlockStart.gif                
年龄校验 OLD#region 年龄校验 OLD
ExpandedSubBlockStart.gifContractedSubBlock.gif                
/**/////如果输入的不是整数,则抛出异常
                //try
                
//{
                
//    Convert.ToInt32(value);
                
//}
                
//catch(Exception ex)
                
//{
                
//    throw new Exception(ex.ToString());
                
//}
                 
ExpandedSubBlockStart.gifContractedSubBlock.gif                
/**/////如果输入的整数不在合理范围同,则也抛出异常

                
//if (value < 0 || value > 200)
                
//{
                
//    throw new Exception("Age must be between 0 and 200");
                
//}
                #endregion

                _age 
= value;
                OnPropertyChanged(
"Age");
            }

        }


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
地址属性#region 地址属性
        
public string Address
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return _address; }
            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (value == _address) return;
                _address 
= value;
                OnPropertyChanged(
"Address");
            }

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
Validator属性#region Validator属性
        
public PersonValidator Validator
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return this._personValidator; }
        }

        
#endregion

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
INotifyPropertyChanged 接口实现#region INotifyPropertyChanged 接口实现
        
public event PropertyChangedEventHandler PropertyChanged;

        
protected void OnPropertyChanged(string name)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (PropertyChanged != null)
                PropertyChanged(
thisnew PropertyChangedEventArgs(name));
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
RaisePropertyChanged方法#region RaisePropertyChanged方法
        
internal void RaisePropertyChanged(string name)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            OnPropertyChanged(name);
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
IEditableObject 接口实现#region IEditableObject 接口实现

        
private  Person _backup;  //用于保存编辑对象的原本
        private  bool _editing;   //处于编辑状态时为true,退出编辑状态时为false

        
void IEditableObject.BeginEdit()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (!_editing)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _editing 
= true;

                
//MemberwiseClone 方法在这里仅做演示,如果在实际应用时,应该用deep copy.
                _backup = this.MemberwiseClone() as Person;  //保存编辑前的内容
            }


        }


        
void IEditableObject.CancelEdit()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (_editing)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//取消当前编辑,恢复编辑前内容
                
//如果要取消当前编辑,请按下Esc键 

                Name 
= _backup.Name;
                Sex 
= _backup.Sex;
                Age 
= _backup.Age;
                Address 
= _backup.Address;
                _editing 
= false;
            }


        }


        
void IEditableObject.EndEdit()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (_editing)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _editing 
= false;
                
this._backup = null;//当前编辑生效

 
                
//当用户结束Edit时,激发我们自定义的ChangesCommitted事件,在此事件中执行我们期望的其它处理工作

                
if (null != ChangesCommitted)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    _fireChangesCommited 
= true;

                    
//this.RootVisual就是Application.Current.RootVisual的值,也就是page control
                    
//所有的子控件都在RootVisual里面,可以通过  Page page = (Page)Application.Current.RootVisual得到这个Page对象。

                    Application.Current.RootVisual.Dispatcher.BeginInvoke(() 
=> _personValidator.Validate()); //调用 Validate方法进行校验

                    
//取消下面的OnChangesCommitted,也即不再在此处提交修改,推迟为由PersonValidator类中来做此项工作,如果校验都通过则提交否则不提交
                    
//  OnChangesCommitted();  
                }


            }

        }


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
数据修改生效确定#region 数据修改生效确定

       
bool _fireChangesCommited;

        
public event EventHandler<EventArgs> ChangesCommitted;

        
protected void OnChangesCommitted()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (null != ChangesCommitted)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                ChangesCommitted(
thisnew EventArgs());
            }

        }

        
#endregion



ContractedSubBlock.gifExpandedSubBlockStart.gif        
PersonValidator 类校验通过事件响应#region  PersonValidator 类校验通过事件响应
        
void _validator_Validated(object sender, EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (_fireChangesCommited)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _fireChangesCommited 
= false;
                
if (_personValidator.IsValid)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    Application.Current.RootVisual.Dispatcher.BeginInvoke(() 
=> OnChangesCommitted());
                }

            }

        }

        
#endregion

    }

}

  修改People类代码如下:

ContractedBlock.gif ExpandedBlockStart.gif Code
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.Collections.ObjectModel; //引入此空间,因为要用到ObservableCollection类
using System.Collections.Generic;

namespace SLApplicationDataTest
ExpandedBlockStart.gifContractedBlock.gif
{
    
public class People : ObservableCollection<Person>
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{

        
private Person emptyPerson;
        
private People peopleData;

ContractedSubBlock.gifExpandedSubBlockStart.gif        
GetTestData方法#region  GetTestData方法
        
public static People GetTestData()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{

            People peopleData 
= new People()
ExpandedSubBlockStart.gifContractedSubBlock.gif          
{
           
            
new Person("Marge""Female"33"SpringVale"),
            
new Person("Tom""Male"8"Toorak"),
            
new Person("Simon""Male"21"RingWood"),
            
new Person("Abby""Male"18"BoxHill")
           }
;

            
return peopleData;
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
GetTestDataList方法#region GetTestDataList方法
        
public static List<Person> GetTestDataList()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return new List<Person>()
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
new Person("Jack""Male"38"ChengDu"),
            
new Person("Marge""Female"33"SpringVale"),
            
new Person("Tom""Male"8"Toorak"),
            
new Person("Simon""Male"21"RingWood"),
            
new Person("Abby""Male"18"BoxHill")
            }
;
        }

        
#endregion


        
public People AddNewPerson(  )
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            emptyPerson 
= new Person();
            emptyPerson.ChangesCommitted 
+= new EventHandler<EventArgs>(emptyPerson_ChangesCommitted);
            
base.InsertItem(this.Count, emptyPerson);
            
return this;
        }


ContractedSubBlock.gifExpandedSubBlockStart.gif        
ChangesCommitted 自定义事件处理过程#region ChangesCommitted 自定义事件处理过程
        
void emptyPerson_ChangesCommitted(object sender, EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            emptyPerson.ChangesCommitted 
-= new EventHandler<EventArgs>(emptyPerson_ChangesCommitted);
            emptyPerson 
= new Person();
            MessageBox.Show(
"本记录行更改已提交!");
            emptyPerson.ChangesCommitted 
+= new EventHandler<EventArgs>(emptyPerson_ChangesCommitted);
            
base.InsertItem(this.Count, emptyPerson);
        }

        
#endregion


    }

}

 

  修改PersonValidator类,其全部代码如下:

ContractedBlock.gif ExpandedBlockStart.gif Code
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
ExpandedBlockStart.gifContractedBlock.gif
{
    
public class PersonValidator:INotifyPropertyChanged 
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ContractedSubBlock.gifExpandedSubBlockStart.gif        
相关常量定义#region 相关常量定义
        
public const string PROPERTY_NAME_ISVALID = "IsValid";
        
public const string PROPERTY_NAME_INVALID = "Invalid";

        
public const string PROPERTY_NAME_NAME = "Name";
        
public const string PROPERTY_NAME_AGE = "Age";
        
public const string PROPERTY_NAME_SEX = "Sex";

        
private Dictionary<stringstring> _errors; //定义一个数据字典用于集中管理校验结果

        
private bool _fireValidated;  //用于配合录入确定时的数据校验

        
private List<string> _propertiesToValidate;

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
年龄属性及年龄校验#region 年龄属性及年龄校验
        
// private bool _invalidAge;

        
public bool InvalidAge
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get 
ExpandedSubBlockStart.gifContractedSubBlock.gif            

                
//return _invalidAge; 
                return _errors.ContainsKey(PROPERTY_NAME_AGE);
            }

            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//if (_invalidAge == value)
                
//    return;
                
//_invalidAge = value;
                
//OnPropertyChanged("InvalidAge");
                if (value)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    RegisterError(PROPERTY_NAME_AGE, 
"年龄必须介于0到200之间!");
                }

                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    ClearError(PROPERTY_NAME_AGE);
                }

            }

        }



        
public void ValidateAge(int newValue)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            InvalidAge 
= (newValue < 0 || newValue > 200);//年龄应该介于0到200之间,如果超过逻辑范围,则返回true,表示校验没通过!
        }


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
姓名属性及姓名校验#region 姓名属性及姓名校验
       
// private bool _invalidName;

        
public bool InvalidName
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get 
ExpandedSubBlockStart.gifContractedSubBlock.gif            

                
//return _invalidName; 
                return _errors.ContainsKey(PROPERTY_NAME_NAME);
            }

            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//if (_invalidName == value) return;
                
//_invalidName = value;
                
//OnPropertyChanged("InvalidName");
                if (value) 
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    RegisterError(PROPERTY_NAME_NAME, 
"请输入您的姓名!"); 
                }
 
                
else 
ExpandedSubBlockStart.gifContractedSubBlock.gif                

                    ClearError(PROPERTY_NAME_NAME); 
                }

            }

        }


        
public void ValidateName(string newValue)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (string.IsNullOrEmpty(newValue)) //姓名输入不能为空
ExpandedSubBlockStart.gifContractedSubBlock.gif
            {
                InvalidName 
= true//如果为空,则返回true
                return;
            }

            InvalidName 
= (0 == newValue.Trim().Length);
        }


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
性别属性及性别校验#region 性别属性及性别校验
        
//private bool _invalidSex;

        
public bool InvalidSex
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get 
ExpandedSubBlockStart.gifContractedSubBlock.gif            

               
// return _invalidSex; 
                return _errors.ContainsKey(PROPERTY_NAME_SEX);
            }

            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//if (_invalidSex == value) return;
                
//_invalidSex = value;
                
//OnPropertyChanged("InvalidSex");
                if (value)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    RegisterError(PROPERTY_NAME_SEX, 
"请输入正确的性别!");
                }

                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    ClearError(PROPERTY_NAME_SEX);
                }

            }

        }


ContractedSubBlock.gifExpandedSubBlockStart.gif            
性别输入校验程序:通过调用WCF服务来完成校验工作#region  性别输入校验程序:通过调用WCF服务来完成校验工作
            
private void ValidateSex(string SexStr)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (string.IsNullOrEmpty(SexStr)) 
ExpandedSubBlockStart.gifContractedSubBlock.gif                

                    InvalidSex 
= true;
                    
return
                }


                SexWCFClient sexCs 
= new SexWCFClient();
                sexCs.SexValidationCompleted 
+= new EventHandler<SexValidationCompletedEventArgs>(sexCs_SexValidationCompleted);
                ((Page)Application.Current.RootVisual).StartWait(
"请稍候,正在校验性别输入!");  //打开等待提示界面,提示用户指定的提示信息
                sexCs.SexValidationAsync(SexStr, SexStr);  //其中第二个SexStr为传入的UserState参数,将在sexCs_SexValidationCompleted中使用
            }


            
public void sexCs_SexValidationCompleted(object sender, SexValidationCompletedEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                ((Page)Application.Current.RootVisual).EndWait(
null); //关闭等待提示界面 
                InvalidSex = !e.Result;   
            }


            
#endregion


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
整体校验属性#region  整体校验属性
       
// private bool _isValid;
        public bool IsValid
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//return _isValid;
                return (0 == _errors.Keys.Count); //当字典中没有任何error记录时,返回true,表示整体校验通过
            }

            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//if (_isValid == value) return;
                
//_isValid = value;
                
//OnPropertyChanged("IsValid");

                OnPropertyChanged(PROPERTY_NAME_ISVALID);
                Application.Current.RootVisual.Dispatcher.BeginInvoke(() 
=> _data.RaisePropertyChanged("Validator"));

               
// _data.RaisePropertyChanged("Validator");
            }

        }


        
#endregion




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

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

ContractedSubBlock.gifExpandedSubBlockStart.gif        
构造函数一#region 构造函数一
        
public PersonValidator(Person data)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _data 
= data;

            
//当它所关联的Person类对象实例的任何属性发生变更时则会激活_data_PropertyChanged事件处理
ContractedSubBlock.gifExpandedSubBlockStart.gif
                OLD#region OLD
            
//_data_PropertyChanged事件处理实际就是对变更的属性值进行数据校验
            
// default valid
            
// _isValid = true;
            #endregion

            
//_data.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(_data_PropertyChanged);
            _data.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Person_PropertyChanged);   
            _errors 
= new Dictionary<stringstring>();

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
构造函数二#region 构造函数二
        
public PersonValidator(Person data, bool defaultInvalid) : this(data)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (defaultInvalid)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
ContractedSubBlock.gifExpandedSubBlockStart.gif                
OLD#region  OLD
                
//_invalidAge = true;
                
//_invalidName = true;
                
//_invalidSex = true;
                
//_isValid = false;
                #endregion

                _errors.Add(PROPERTY_NAME_AGE, PROPERTY_NAME_AGE); 
                _errors.Add(PROPERTY_NAME_SEX, PROPERTY_NAME_SEX);
                _errors.Add(PROPERTY_NAME_NAME, PROPERTY_NAME_NAME);
            }

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
当Person类对象的任一属性发生改变时重新进行校验#region 当Person类对象的任一属性发生改变时重新进行校验
        
void _data_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (e.PropertyName == "IsValid")
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }

            
switch (e.PropertyName)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
ContractedSubBlock.gifExpandedSubBlockStart.gif                
OLD#region OLD
                
//case "Age":
                
//    ValidateAge(_data.Age);
                
//    break;
                
//case "Name":
                
//    ValidateName(_data.Name);
                
//    break;
                
//case "Sex":
                
//    ValidateSex(_data.Sex);
                
//    break;
                #endregion

                
case PROPERTY_NAME_AGE: ValidateAge(_data.Age); break;
                
case PROPERTY_NAME_NAME: ValidateName(_data.Name); break;
                
case PROPERTY_NAME_SEX: ValidateSex(_data.Sex); break;
            }

        }

        
#endregion


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
PersonValidator类的Validate方法#region PersonValidator类的Validate方法
        
public void Validate()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _fireValidated 
= true;

ExpandedSubBlockStart.gifContractedSubBlock.gif            _propertiesToValidate 
= new List<string>() 
                PROPERTY_NAME_INVALID 
+ PROPERTY_NAME_AGE, 
                PROPERTY_NAME_INVALID 
+ PROPERTY_NAME_SEX, 
                PROPERTY_NAME_INVALID 
+ PROPERTY_NAME_NAME }
;


            ValidateAge(_data.Age);
            ValidateName(_data.Name);
            ValidateSex(_data.Sex);
        }

        
#endregion




ContractedSubBlock.gifExpandedSubBlockStart.gif        
INotifyPropertyChanged Members#region INotifyPropertyChanged Members

        
public event PropertyChangedEventHandler PropertyChanged;

        
protected void OnPropertyChanged(string name)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (PropertyChanged != null)
            PropertyChanged(
thisnew PropertyChangedEventArgs(name));

            
if (_fireValidated && AllPropertiesValidated(name))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _fireValidated 
= false;
                Application.Current.RootVisual.Dispatcher.BeginInvoke(() 
=> OnValidated());
            }

        }

        
#endregion



ContractedSubBlock.gifExpandedSubBlockStart.gif        
获取对应字段的校验出错提示信息#region 获取对应字段的校验出错提示信息
        
public string this[string propertyName] 
ExpandedSubBlockStart.gifContractedSubBlock.gif         
{            
             
get 
ExpandedSubBlockStart.gifContractedSubBlock.gif             
{                
                 
if (_errors.ContainsKey(propertyName)) 
ExpandedSubBlockStart.gifContractedSubBlock.gif                 
{                   
                     
return _errors[propertyName];                
                 }
 
                 
else 
ExpandedSubBlockStart.gifContractedSubBlock.gif                 
{                  
                     
return null;// propertyName;                
                 }
            
             }

         }

        
#endregion



ContractedSubBlock.gifExpandedSubBlockStart.gif        
error Dictionary 字典管理#region  error Dictionary 字典管理

ContractedSubBlock.gifExpandedSubBlockStart.gif        
添加与更新Dictionary记录#region 添加与更新Dictionary记录
        
public void RegisterError(string propertyName, string message) 
ExpandedSubBlockStart.gifContractedSubBlock.gif        

            
if (_errors.ContainsKey(propertyName)) 
ExpandedSubBlockStart.gifContractedSubBlock.gif            

                _errors[propertyName] 
= message; //更新对应的error信息对
            }
 
            
else 
ExpandedSubBlockStart.gifContractedSubBlock.gif            

                _errors.Add(propertyName, message);  
//添加新的error信息对
            }
 
            OnPropertyChanged(PROPERTY_NAME_INVALID 
+ propertyName); 
            
//IsValid = false;
            Application.Current.RootVisual.Dispatcher.BeginInvoke(() => IsValid = false);

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif         
移除Dictionary记录#region 移除Dictionary记录
         
public void ClearError(string propertyName) 
ExpandedSubBlockStart.gifContractedSubBlock.gif        

            
if (_errors.ContainsKey(propertyName)) 
ExpandedSubBlockStart.gifContractedSubBlock.gif            

                _errors.Remove(propertyName);  
//删除指定的error信息对
            }
 
            OnPropertyChanged(PROPERTY_NAME_INVALID 
+ propertyName); 
           
// IsValid = true;
            Application.Current.RootVisual.Dispatcher.BeginInvoke(() => IsValid = true);

        }

        
#endregion


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
Person_PropertyChanged 时的校验#region Person_PropertyChanged 时的校验
         
void Person_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif         
{
             
if (e.PropertyName == "IsValid")
ExpandedSubBlockStart.gifContractedSubBlock.gif             
{
                 
return;
             }

             
switch (e.PropertyName)
ExpandedSubBlockStart.gifContractedSubBlock.gif             
{
                 
case PROPERTY_NAME_AGE:
                     ValidateAge(_data.Age);
                     
break;
                 
case PROPERTY_NAME_NAME:
                     ValidateName(_data.Name);
                     
break;
                 
case PROPERTY_NAME_SEX:
                     ValidateSex(_data.Sex);
                     
break;

             }

         }

         
#endregion



         
public bool AllPropertiesValidated(string propertyValidated)
ExpandedSubBlockStart.gifContractedSubBlock.gif         
{
             _propertiesToValidate.Remove(propertyValidated);
             
return (_propertiesToValidate.Count == 0);
         }


         
public event EventHandler<EventArgs> Validated;

         
protected void OnValidated()
ExpandedSubBlockStart.gifContractedSubBlock.gif         
{
             
if (null != Validated)
ExpandedSubBlockStart.gifContractedSubBlock.gif             
{
                 Validated(
thisnew EventArgs());
             }

         }

    }

}

 

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

 

ContractedBlock.gif ExpandedBlockStart.gif Code
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
ExpandedBlockStart.gifContractedBlock.gif
{
    
public partial class Page : UserControl
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        People mypeople;

        
public Page()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            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)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ContractedSubBlock.gifExpandedSubBlockStart.gif            
取得数据源数据并绑定到DataGrid控件上#region 取得数据源数据并绑定到DataGrid控件上
            mypeople 
= People.GetTestData();
            
this.dgPeople.ItemsSource = mypeople;
            
#endregion


        }


ContractedSubBlock.gifExpandedSubBlockStart.gif        
通过按钮添加新记录行#region 通过按钮添加新记录行
        
void addButton_Click(object sender, RoutedEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
           
// mypeople.Add(new Person());
            mypeople = mypeople.AddNewPerson();
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
通过按钮删除记录#region 通过按钮删除记录
        
void deleteButton_Click(object sender, RoutedEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            DeletePerson();
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
删除记录子程序#region 删除记录子程序
        
private void DeletePerson()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (null == this.dgPeople.SelectedItem)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }

            Person person 
= this.dgPeople.SelectedItem as Person;
            
if (null == person)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }

            mypeople.Remove(person);
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
处理键盘响应事件#region 处理键盘响应事件
        
void peopleDataGrid_KeyDown(object sender, KeyEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ContractedSubBlock.gifExpandedSubBlockStart.gif            
如果是Insert键,则做插入新行操作#region 如果是Insert键,则做插入新行操作
            
if (Key.Insert == e.Key)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                mypeople.Add(
new Person());
            }

            
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif            
如果是Delete键,则做删除操作#region 如果是Delete键,则做删除操作
            
if (Key.Delete == e.Key)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                DeletePerson();
            }

            
#endregion

        }

        
#endregion



ContractedSubBlock.gifExpandedSubBlockStart.gif        
校验错误处理程序#region 校验错误处理程序
        
private void TextBox_BindingValidationError(object sender, ValidationErrorEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{

            
if (e.Action == ValidationErrorEventAction.Added)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//如果校验出错,则抛出错误提示窗口
                ((Control)e.OriginalSource).Background = new SolidColorBrush(Colors.Red);
                ((Control)e.OriginalSource).SetValue(ToolTipService.ToolTipProperty, e.Error.Exception.Message);
                ((Control)e.OriginalSource).Focus();
                
this.Dispatcher.BeginInvoke(() => HtmlPage.Window.Alert(e.Error.Exception.Message));


            }

            
else if (e.Action == ValidationErrorEventAction.Removed)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//如果校验通过,则做如下处理
                ((Control)e.OriginalSource).Background = new SolidColorBrush(Colors.White);
                ((Control)e.OriginalSource).SetValue(ToolTipService.ToolTipProperty, 
null);
            }


        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
打开与关闭“等待校验窗口”#region  打开与关闭“等待校验窗口”
        
public void StartWait(string message)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
this.myWaitingSexValidateScreen.DataContext = message;
            
this.myWaitingSexValidateScreen.StartWait();
        }


        
public void EndWait(string message)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
this.myWaitingSexValidateScreen.DataContext = message;
            
this.myWaitingSexValidateScreen.StopWait();
        }

        
#endregion


        
private void dgPeople_BindingValidationError(object sender, ValidationErrorEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (e.Action == ValidationErrorEventAction.Added)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                Person person 
= ((Control)e.OriginalSource).DataContext as Person;
                
if (null != person && null != ((Control)e.OriginalSource).Tag)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    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)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                Person person 
= ((Control)e.OriginalSource).DataContext as Person;
                
if (null != person && null != ((Control)e.OriginalSource).Tag)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    person.Validator.ClearError(((Control)e.OriginalSource).Tag.ToString());
                }

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


        }

    }

}

 
   从代码可以看到,我们在此方法中不再直接激活ChangesCommitted事件,而是先由PersonValidator 类进行校验,校验通过后,由Person类的中的_validator_Validated方法来激活ChangesCommitted事件。如果校验没有通过,则不激活ChangesCommitted事件。

  生成项目并运行,可以看到
  1、当新行数据录入校验没通过时,程序会提示并不会自动添加新行,如下图

                         
2、当新行数据录入校验通过后,程序会自动添加一新行,如下图:

                        先显示提交修改的数据

                        
        再在最后自动添加一新行,如下图:
                                                 

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

转载于:https://www.cnblogs.com/wsdj-ITtech/archive/2009/09/11/1564642.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值