上一篇,着重介绍了Silverlight客户端同步数据验证机制,演示了IDataErrorInfo接口的实现方法。在一些实际的Silverlight企业级项目中,我们经常会遇到通过服务对数据进行验证,另外应用在验证的同时,不会影响其他功能的运行,也就是我们常提及的异步 *** 作,这样的需求IDataErrorInfo接口和前期我们讨论过的DataAnotation验证机制都无法实现。另外在一些项目中,开发人员会绑定多个错误到一个数据成员,而IDataErrorInfo和DataAnotation也无法实现。Silverlight 4中,微软引入一个新的接口INotifyDataErrorInfo,该接口的实现,可以轻松的解决以上两个问题。
INotifyDataErrorInfo接口的概述
INotifyDataErrorInfo接口和IDataErrorInfo相同,命名空间都是System.ComponentModel。
该接口是为数据成员提供自定义的同步或者异步验证支持。最常用的是对异步验证的支持,另外,可支持单属性中绑定多个错误信息。
INotifyDataErrorInfo接口具有一个属性,一个方法,一个事件,分别是:
HasErrors@H_301_29@, 这个属性判断当前对象中是否有错误,如果返回True则说明对象出现验证错误,反之则False。
方法:
GetErrors@H_301_29@, 这个方法负责返回特定验证成员中所有的验证错误信息,如果Propertyname参数为null或者string.empty,该方法将返回一个错误到全局对象中。
事件:
ErrorsChanged@H_301_29@,该事件与上篇我们提及的PropertyChanged事件相似。当添加,删除,修改验证错误时,将激活该事件通知绑定系统,更新UI。
INotifyDataErrorInfo接口实例演示
实现INotifyDataErrorInfo接口,支持服务器端异步验证,所以,本实例将创建一个Web服务,演示该接口验证效果。
本篇实例,我们仍旧使用SilverlightValIDationDemo项目,为了不和过去的验证方法冲突,这里我们创建一个新的数据成员类Staff,该类实现INotifyDataErrorInfo接口和INotifyPropertyChanged接口. 其默认代码如下,后面我们将逐渐完善这些代码,
@H_301_29@ #region@H_301_29@ INotifyDataErrorInfo Members@H_301_29@
@H_301_29@ public@H_301_29@ @H_301_29@ event@H_301_29@ EventHandler@H_301_29@ <@H_301_29@ DataErrorsChangedEventArgs@H_301_29@ >@H_301_29@ ErrorsChanged;
@H_301_29@ public@H_301_29@ System.Collections.IEnumerable GetErrors(@H_301_29@ string@H_301_29@ propertyname)
{
@H_301_29@ throw@H_301_29@ @H_301_29@ new@H_301_29@ NotImplementedException();
}
@H_301_29@ public@H_301_29@ @H_301_29@ bool@H_301_29@ HasErrors
{
@H_301_29@ get@H_301_29@ { @H_301_29@ throw@H_301_29@ @H_301_29@ new@H_301_29@ NotImplementedException(); }
}
@H_301_29@ #endregion@H_301_29@
@H_301_29@ #region@H_301_29@ INotifyPropertyChanged Members@H_301_29@
@H_301_29@ public@H_301_29@ @H_301_29@ event@H_301_29@ PropertyChangedEventHandler PropertyChanged;
@H_301_29@ #endregion@H_301_29@
另外定义一个新的数据成员,Username
@H_301_29@ #region@H_301_29@ data memebers@H_301_29@
@H_301_29@ private@H_301_29@ @H_301_29@ string@H_301_29@ _username;
@H_301_29@ public@H_301_29@ @H_301_29@ string@H_301_29@ Username
{
@H_301_29@ get@H_301_29@ { @H_301_29@ return@H_301_29@ _username; }
@H_301_29@ set@H_301_29@
{
_username @H_301_29@ =@H_301_29@ value;
}
}
@H_301_29@ #endregion@H_301_29@
完成以上的客户端准备步骤,我们首先到Web服务器端创建一个Silverlight enabled WCF Service, ValIDationService。 这里我不再演示具体的创建步骤,如果不会创建的,请参考这里:图文详解Silverlight访问MSSQL数据库
在服务端,我们创建简单的验证代码,如下
[ServiceContract(namespace @H_301_29@ =@H_301_29@ @H_301_29@ ""@H_301_29@ )]
[AspNetCompatibilityRequirements(RequirementsMode @H_301_29@ =@H_301_29@ AspNetCompatibilityRequirementsMode.Allowed)]
@H_301_29@ public@H_301_29@ @H_301_29@ class@H_301_29@ ValIDationService
{
[OperationContract]
@H_301_29@ public@H_301_29@ @H_301_29@ bool@H_301_29@ ValIDationUsername(@H_301_29@ string@H_301_29@ username)
{
@H_301_29@ if@H_301_29@ (username @H_301_29@ ==@H_301_29@ @H_301_29@ "@H_301_29@ jv9@H_301_29@ "@H_301_29@ )
@H_301_29@ return@H_301_29@ @H_301_29@ true@H_301_29@ ;
@H_301_29@ else@H_301_29@
@H_301_29@ return@H_301_29@ @H_301_29@ false@H_301_29@ ;
}
}@H_301_29@
创建完毕后,编译SilverlightValIDationDemo.Web项目,然后回到Silverlight客户端,添加一个新的服务引用,
搜索到刚创建的ValIDationService服务,添加到客户端,Visual Studio 2010会自动创建客户端配置文件ServiceReferences.ClIEntConfig,
到这里一个WCF服务已经创建成功,下面,修改Staff类,
之前,我们已经创建了新的数据成员Username,另外执行INotifyDataErrorInfo接口,自动生成ErrorsChanged事件,GetErrors方法和HasErrors属性。
首先,需要对GetErrors方法进行重构,创建全局变量_valIDationErrors,承载验证错误信息集合.
@H_301_29@ private@H_301_29@ Dictionary@H_301_29@ <@H_301_29@ string@H_301_29@ , ObservableCollection@H_301_29@ <@H_301_29@ string@H_301_29@ >>@H_301_29@ _valIDationErrors;
@H_301_29@ public@H_301_29@ System.Collections.IEnumerable GetErrors(@H_301_29@ string@H_301_29@ propertyname)
{
@H_301_29@ if@H_301_29@ (@H_301_29@ !@H_301_29@ string@H_301_29@ .IsNullOrEmpty(propertyname))
{
@H_301_29@ if@H_301_29@ (_valIDationErrors.ContainsKey(propertyname))
@H_301_29@ return@H_301_29@ _valIDationErrors[propertyname];
@H_301_29@ else@H_301_29@
@H_301_29@ return@H_301_29@ @H_301_29@ null@H_301_29@ ;
}
@H_301_29@ else@H_301_29@
@H_301_29@ return@H_301_29@ null@H_301_29@;
}@H_301_29@
然后,对HasErrors属性进行重构,,判断是否有验证错误,
public@H_301_29@ @H_301_29@ bool@H_301_29@ HasErrors{
@H_301_29@ get@H_301_29@
{@H_301_29@
@H_301_29@ foreach@H_301_29@ (@H_301_29@ string@H_301_29@ key @H_301_29@ in@H_301_29@ _valIDationErrors.Keys)
{
@H_301_29@ if@H_301_29@ (_valIDationErrors[key].Count @H_301_29@ >@H_301_29@ @H_301_29@ @H_482_502@0@H_301_29@ )
@H_301_29@ return@H_301_29@ @H_301_29@ true@H_301_29@ ;
}
@H_301_29@ return@H_301_29@ @H_301_29@ false@H_301_29@ ;
}
}@H_301_29@
创建构造函数,和初始化错误集合,
@H_301_29@ public@H_301_29@ Staff()
{
_valIDationErrors @H_301_29@ =@H_301_29@ @H_301_29@ new@H_301_29@ Dictionary@H_301_29@ <@H_301_29@ string@H_301_29@ , ObservableCollection@H_301_29@ <@H_301_29@ string@H_301_29@ >>@H_301_29@ ();
GenerateErrorsCollection(@H_301_29@ "@H_301_29@ Username@H_301_29@ "@H_301_29@ );
}
@H_301_29@ #endregion@H_301_29@
@H_301_29@ #region@H_301_29@ private methods@H_301_29@
@H_301_29@ private@H_301_29@ @H_301_29@ voID@H_301_29@ GenerateErrorsCollection(@H_301_29@ string@H_301_29@ propertyname)
{
@H_301_29@ if@H_301_29@ (@H_301_29@ !@H_301_29@ _valIDationErrors.ContainsKey(propertyname))
{
_valIDationErrors.Add(propertyname, @H_301_29@ new@H_301_29@ ObservableCollection@H_301_29@ <@H_301_29@ string@H_301_29@ >@H_301_29@ ());
}
}@H_301_29@
添加调用服务客户端代码,
@H_301_29@ private@H_301_29@ @H_301_29@ voID@H_301_29@ ValIDateUsernameandPasswordAsync(@H_301_29@ string@H_301_29@ username)
{
var clIEnt @H_301_29@ =@H_301_29@ @H_301_29@ new@H_301_29@ ValIDationService.ValIDationServiceClIEnt();
clIEnt.ValIDationUsernameCompleted @H_301_29@ +=@H_301_29@ (o, e) @H_301_29@ =>@H_301_29@
{
_valIDationErrors[@H_301_29@ "@H_301_29@ Username@H_301_29@ "@H_301_29@ ].Clear();
@H_301_29@ if@H_301_29@ (e.Result)
{
_username @H_301_29@ =@H_301_29@ username;
NotifyPropertyChanged(@H_301_29@ "@H_301_29@ Username@H_301_29@ "@H_301_29@ );
}
@H_301_29@ else@H_301_29@
{
_valIDationErrors[@H_301_29@ "@H_301_29@ Username@H_301_29@ "@H_301_29@ ].Add(@H_301_29@ "@H_301_29@ 服务器端返回错误,用户名必须是jv9@H_301_29@ "@H_301_29@ );
}
@H_301_29@ if@H_301_29@ (ErrorsChanged @H_301_29@ !=@H_301_29@ @H_301_29@ null@H_301_29@ )
{
ErrorsChanged(@H_301_29@ this@H_301_29@ , @H_301_29@ new@H_301_29@ DataErrorsChangedEventArgs(@H_301_29@ "@H_301_29@ Username@H_301_29@ "@H_301_29@ ));
}
};
clIEnt.ValIDationUsernameAsync(username);
}@H_301_29@
在数据成员中,添加验证方法调用,
@H_301_29@ #region@H_301_29@ data memebers@H_301_29@