Silverlight实例教程 - Validation客户端同步数据验证

Silverlight实例教程 - Validation客户端同步数据验证

前文介绍过Silverlight Validation中两个数据验证机制,ValidatesOnExceptions异常捕获验机制DataAnnotation验证机制,这两种验证机制,是在Silverlight 3 Validation Framework推出的,其运行方式类似,都是当异常抛出后,应用对异常信息进行捕获,并显示在客户端。在Silverlight 4中,Silverlight Validation有相对的改进,本篇将介绍Silverlight 4中新加入的验证机制功能,IDataErrorInfo客户端同步验证机制。

Silverlight 4 IDataErrorInfo接口概述

相信熟悉WPF的开发人员都知道,WPF也具有IdataErrorInfo接口,其接口可以无需抛出任何异常,即可对数据进行验证。而Silverlight的IDataErrorInfo接口就是从WPF中转化来的。与前面两种验证机制相比,Silverlight 4 IDataErrorInfo提供的同步验证方式,不再需要基于异常抛出的基础上来激活验证,简单的理解,就是当值验证失败的时候,不会抛出任何异常信息。这种验证机制,相对前两种验证机制来说更加灵活。

Silverlight 4 IDataErrorInfo接口类成员

IDataErrorInfo接口,位于System.ComponentModel命名空间。该接口主要被应用在需要对其进行验证的数据成员类。

代码
1 #region IDataErrorInfoMembers
2
3 public string Error
4 {
5 get { throw new NotImplementedException();}
6 }
7
8 public string this [ string columnName]
9 {
10 get { throw new NotImplementedException();}
11 }
12
13 #endregion

IDataErrorInfo接口具有两个属性

1. Error: 该属性为验证设置属性错误提示信息;

2. Item: 该属性为错误信息集合,其中索引值为属性名,将其对应的错误信息,设置到指定的被验证控件中;

从MSDN对IdataErrorInfo接口的解释中可以看到,IDataErrorInfo接口,没有任何事件方法被预先定义。也就是说,IDataErrorInfo接口本身不具备自动激活验证功能。简单的可以理解成为,当验证错误产生时,该错误信息不会自动捕获,然后显示到用户客户端上。解决该问题,需要引入另外一个接口INotifyPropertyChanged。对Silverlight早期版本熟悉的开发人员,应该对INotifyPropertyChanged接口并不陌生,该接口主要功能是当数据成员改变时发出通知到客户端,是Silverlight中最常用的一个接口,这里对该接口不再赘述。

public class Customer:INotifyPropertyChanged

public event PropertyChangedEventHandlerPropertyChanged;

private void NotifyPropertyChanged(Stringinfo)
{
if (PropertyChanged != null )
{
PropertyChanged(
this , new PropertyChangedEventArgs(info));
}
}

public string CustomerName
{
get
{
return this .customerNameValue;
}

set
{
if (value != this .customerNameValue)
{
this .customerNameValue = value;
NotifyPropertyChanged(
" CustomerName " );
}
}
}

在使用了INotifyPropertyChanged接口后,每当数据成员验证错误产生时,都会执行IDataErrorInfo接口,检测Error和Item属性。但是仅仅使用INotifyPropertyChanged接口,还无法正常将错误信息显示在客户端,同时也需要在客户端添加新的绑定验证属性ValidatesOnDataErrors, 该属性在默认绑定情况下是False,如果使用IDataErrorInfo接口,则需要使用True,这时,客户端才会显示IDataErrorInfo接口被执行后产生的验证错误信息。

< TextBoxText = " {BindingCustomerName,Mode=TwoWay,ValidatesOnDataErrors=true} " />

讲到这里,我们可以结合前两篇讲解的绑定验证属性,来理解IDataErrorInfo接口。

使用IDataErrorInfo接口,必须结合INotifyPropertyChanged接口使用,否则UI无法获取到相对应属性的错误关联信息。

而使用IDataErrorInfo接口绑定验证属性时,在客户端控件内容绑定中使用ValidatesOnDataErrors = True,

另外,如果需要使用BindingValidationError事件,在客户端控件内容中,需要再绑定NotifyOnValidationError = True,

如果需要对异常进行捕获相应,同时,也需要绑定ValidatesOnExceptions = True。

IDataErrorInfo接口使用实例演示

本实例仍旧使用上一篇的实例代码,在其基础上添加对IDataErrorInfo接口的调用,

首先在User数据成员类中,执行IDataErrorInfo和INotifyPropertyChanged接口

#region IDataErrorInfoMembers

private string _dataError = string .Empty;
public string Error
{
get { return _dataError;}
}

private Dictionary < string , string > _dataErrors = new Dictionary < string , string > ();
public string this [ string columnName]
{
get
{
if (_dataErrors.ContainsKey(columnName))
return _dataErrors[columnName];
else
return null ;
}
}

#endregion

#region INotifyPropertyChangedMembers

public event PropertyChangedEventHandlerPropertyChanged;
protected void NotifyPropertyChanged( string propertyName)
{
if (PropertyChanged != null )
PropertyChanged(
this , new PropertyChangedEventArgs(propertyName));
}

#endregion

其中IDataErrorInfo中定义的Dictionary是验证错误集合。而INotifyPropertyChanged是最简单的当数据成员改变时返回通知到客户端,其中没有过多的逻辑代码。

我们使用最简单的数据成员生成一个验证错误,IDataErrorInfo捕获显示作为演示,

在User类中,添加一个Address地址数据成员,

private string _address;
public string address
{
get
{
return _address;
}
set
{
_address
= value;
}
}

然后在set中添加简单的逻辑代码,

private string _address;
public string address
{
get
{
return _address;
}
set
{
if ( string .IsNullOrEmpty(value))
_dataErrors[
" address " ] = " 地址必须填写 " ;
else if (value.Trim().Length < 6 )
_dataErrors[
" address " ] = " 地址至少6个字 " ;
else
if (_dataErrors.ContainsKey( " address " ))
_dataErrors.Remove(
" address " );

_address
= value;
NotifyPropertyChanged(
" address " );
}
}

修改前台,添加新的输入框,另外绑定输入框内容到address,

< StackPanel Orientation ="Horizontal" Margin ="5" >
< TextBlock Text ="地址:" VerticalAlignment ="Center" />
< TextBox x:Name ="txtAddress" Width ="200" DataContext =" {BindingSource={StaticResourceUserDataContext}} " Text =" {BindingPath=address,Mode=TwoWay,ValidatesOnDataErrors=True} " />
</ StackPanel >

其运行结果为:

下面,我们做一个较为复杂一些的数据验证,

学生成绩对应表

A -90-100分

B - 80-89分

C - 70-79分

D - 60-69分

F- 0-59分

在这个实例中,我们对多个数据成员进行客户端数据验证。

添加两个新数据成员,gradelevel和graderange,其中使用独立的验证函数ValidateGradeLevelandRange进行数据验证,

private string _gradelevel;
public string gradelevel
{
get { return _gradelevel;}
set
{
if (ValidateGradeLevelandRange(value,graderange))
{
_gradelevel
= value;
NotifyPropertyChanged(
" gradelevel " );
}
}
}

private decimal _graderange;
public decimal graderange
{
get { return _graderange;}
set
{
if (ValidateGradeLevelandRange(gradelevel,value))
{
_graderange
= value;
NotifyPropertyChanged(
" graderange " );
}
}
}

#region CustomizeValidation
private bool ValidateGradeLevelandRange( string level, decimal range)
{
bool isValid = false ;

if (level == null )
{
_dataErrors[
" gradelevel " ] = " 成绩等级必须是A,B,C,D,F " ;
return false ;
}
else
{
switch (level.ToUpper())
{
case " A " :
isValid
= (range >= 90 && range <= 100 );
break ;
case " B " :
isValid
= (range >= 80 && range <= 89 );
break ;
case " C " :
isValid
= (range >= 70 && range <= 79 );
break ;
case " D " :
isValid
= (range >= 60 && range <= 69 );
break ;
case " F " :
isValid
= (range >= 0 && range <= 59 );
break ;
default :
_dataErrors[
" gradelevel " ] = " 成绩等级必须是A,B,C,D,F " ;
return false ;
}
}

if (isValid)
{
if (_dataErrors.ContainsKey( " gradelevel " ))
_dataErrors.Remove(
" gradelevel " );
if (_dataErrors.ContainsKey( " graderange " ))
_dataErrors.Remove(
" graderange " );
}
else
{
_dataErrors[
" gradelevel " ] = " 成绩等级和成绩范围不符合 " ;
_dataErrors[
" graderange " ] = " 成绩范围和成绩等级不符合 " ;
}

return isValid;
}
#endregion

在前台添加两个成绩输入框,

< StackPanel Orientation ="Horizontal" Margin ="5" >
< TextBlock Text ="成绩等级:" VerticalAlignment ="Center" />
< TextBox x:Name ="txtGradeLevel" Width ="200" DataContext =" {BindingSource={StaticResourceUserDataContext}} " Text =" {BindingPath=gradelevel,Mode=TwoWay,ValidatesOnDataErrors=True,NotifyOnValidationError=False,ValidatesOnExceptions=True} " />
</ StackPanel >
< StackPanel Orientation ="Horizontal" Margin ="5" >
< TextBlock Text ="成绩范围:" VerticalAlignment ="Center" />
< TextBox x:Name ="txtGradeRange" Width ="200" DataContext =" {BindingSource={StaticResourceUserDataContext}} " Text =" {BindingPath=graderange,Mode=TwoWay,ValidatesOnDataErrors=True,NotifyOnValidationError=False,ValidatesOnExceptions=True} " />
</ StackPanel >

其最终运行结果如下:

今天内容讲到这里了。

源代码下载

欢迎大家加入"专注Silverlight" 技术讨论群:

32679955(六群)
23413513(五群)
32679922(四群)
100844510(三群)
37891947(二群)
22308706(一群)

你可能感兴趣的:(silverlight)