使用 Castal DynamicProxy 简化 Silverlight 数据绑定

简介:

大家都知道, 在使用 Silverlight 数据绑定的时候, 为了使源对象的更改能够传播到目标,源必须实现 INotifyPropertyChanged 接口。INotifyPropertyChanged 具有 PropertyChanged 事件,该事件通知绑定引擎源已更改,以便绑定引擎可以更新目标值。

下面是一个典型的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public  class  UserModel : INotifyPropertyChanged {
 
    private  string  _firstName;
    private  string  _lastName;
 
    public  string  FirstName {
       get  {
          return  this ._firstName;
       }
       set  {
          this ._firstName = value;
          this .NotifyPropertyChanged( "FirstName" );
       }
    }
 
    public  string  LastName {
       get  {
          return  this ._lastName;
       }
       set  {
          this ._lastName = value;
          this .NotifyPropertyChanged( "LastName" );
       }
    }
 
    public  event  PropertyChangedEventHandler PropertyChanged;
 
    protected  void  NotifyPropertyChanged( string  propertyName) {
       if  ( this .PropertyChanged != null ) {
          this .PropertyChanged( this , new  PropertyChangedEventArgs(propertyName));
       }
    }
}

在这个例子中,设置 FirstName 、LastName 时,需要手工激发 PropertyChanged 事件, 通知绑定引擎,因此, 如果数据源中属性比较多的时候, 是比较烦人的, 每个属性的 Setter 都需要激发一下 PropertyChanged 事件, 而且不能使用 C#  自带的自动属性特性。 当然, 可以自己设置一个代码段 snippet  来解决, 但是,重复的激发 PropertyChanged 事件的代码依然存在, 这不是我们的目标。

前段时间看到有人在抱怨 Silverlight 的数据绑定,说必须要实现 INotifyPropertyChanged 接口, 而且还要手工调用 NotifyPropertyChanged 事件等等, 我想说的是, 借助 Castal DynamicProxy 提供的拦截技术,可以把手工调用 NotifyPropertyChanged 事件的代码省掉。

INotifyPropertyChanged 接口是 Silverlight 数据绑定必须的, 这一点我们无法改变。因此需要先创建一个 BaseModel , 并让其实现 INotifyPropertyChanged 接口,代码如下:

1
2
3
4
5
6
7
8
9
10
public  class  BaseModel : INotifyPropertyChanged {
 
    public  event  PropertyChangedEventHandler PropertyChanged;
 
    public  void  NotifyPropertyChanged( string  propertyName) {
       if  ( this .PropertyChanged != null ) {
          this .PropertyChanged( this , new  PropertyChangedEventArgs(propertyName));
       }
    }
}

接下来为 BaseModel 写一个拦截器, 让所有继承自 BaseModel 的类在设置属性之后自动激发 NotifyPropertyChanged 事件, 拦截器代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public  class  NotifyPropertyChangedInterceptor : StandardInterceptor {
 
    protected  override  void  PostProceed(IInvocation invocation) {
       base .PostProceed(invocation);
       var  methodName = invocation.Method.Name;
       // 这里可能不是很完善, 属性的 Setter 一般都是以 set_ 开头的,
       // 应该有更好的判断方法。
       if  (methodName.StartsWith( "set_" )) {
          var  propertyName = methodName.Substring(4);
          var  target = invocation.Proxy as  BaseModel;
          if  (target != null ) {
             target.NotifyPropertyChanged(propertyName);
          }
       }
    }
}

拦截器的代码很简单, 而且是可以扩展的, 相信都能看懂, 我们还需要一个 ModelHelper , 来方便的创建 Proxy , ModelHelper 的代码如下:

1
2
3
4
5
6
7
8
9
public  static  class  ModelHelper {
 
    private  static  readonly  ProxyGenerator ProxyGenerator = new  ProxyGenerator();
    private  static  readonly  NotifyPropertyChangedInterceptor Interceptor = new  NotifyPropertyChangedInterceptor();
 
    public  static  T CreateProxy≶T>(T obj) where  T : class , INotifyPropertyChanged {
       return  ProxyGenerator.CreateClassProxyWithTarget(obj, Interceptor);
    }
}

有了 ModelHelper , 可以说是万事俱备了, 我们来重写上边的 UserModel , UserModel 最终的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public  class  UserModel : BaseModel {
 
    public  virtual  string  FirstName {
       get ;
       set ;
    }
 
    public  virtual  string  LastName {
       get ;
       set ;
    }
}

最后,使用 UserModel 的代码是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
public  partial  class  MainPage : UserControl {
 
    public  MainPage() {
       InitializeComponent();
 
       // 不能直接使用 UserModel, 要通过 ModelHelper 创建一个 Proxy 才行。
       var  dataContext = ModelHelper.CreateProxy( new  UserModel());
       dataContext.FirstName = "Zhang" ;
       dataContext.LastName = "ZhiMin" ;
 
       this .DataContext = dataContext;
    }
}

我们不能改变环境, 但是可以改变自己, 因此,我们应该多一些思考,少一些抱怨。

本文的内容虽然是针对 Silverlight 数据绑定而写的, 对于 WPF 数据绑定也很适用。

张志敏所有文章遵循创作共用版权协议,要求署名、非商业 、保持一致。在满足创作共用版权协议的基础上可以转载,但请以超链接形式注明出处。

本博客已经迁移到 GitHub , 围观地址: http://beginor.github.io/

本文转自张志敏博客园博客,原文链接:http://www.cnblogs.com/beginor/archive/2011/03/07/1974706.html ,如需转载请自行联系原作者
相关文章
|
6月前
|
XML JavaScript 前端开发
SAP UI5 的数据绑定语法概述
SAP UI5 的数据绑定语法概述
34 0
C# Xamarin数据绑定入门基础
C# Xamarin数据绑定入门基础
125 0
C# Xamarin数据绑定入门基础
|
XML 自然语言处理 JavaScript
深入学习SAP UI5框架代码系列之七:控件数据绑定的三种模式 - One Way, Two Way和OneTime实现原理比较
深入学习SAP UI5框架代码系列之七:控件数据绑定的三种模式 - One Way, Two Way和OneTime实现原理比较
228 0
深入学习SAP UI5框架代码系列之七:控件数据绑定的三种模式 - One Way, Two Way和OneTime实现原理比较
|
XML 存储 Web App开发
深入学习SAP UI5框架代码系列之六:SAP UI5控件数据绑定的实现原理
深入学习SAP UI5框架代码系列之六:SAP UI5控件数据绑定的实现原理
150 0
深入学习SAP UI5框架代码系列之六:SAP UI5控件数据绑定的实现原理
|
前端开发 C#
【我们一起写框架】MVVM的WPF框架(二)—绑定
MVVM的特点之一是实现数据同步,即,前台页面修改了数据,后台的数据会同步更新。 上一篇我们已经一起编写了框架的基础结构,并且实现了ViewModel反向控制Xaml窗体。 那么现在就要开始实现数据同步了。
1478 0
|
前端开发 C# 架构师
【我们一起写框架】MVVM的WPF框架(三)—数据控件
这世上,没人能一次性写出完美无缺的框架;因为,任何一个框架都需要项目的淬炼,然后才能升华,趋近完美。 所以,框架是个反复修改的东西,最终形成的东西。 如果你学了一点技术,觉得自己可以写出框架了,觉得自己有架构师的能力,然而自己总是怀才不遇——那一定是你的错觉。
1148 0
|
前端开发 架构师 程序员
【我们一起写框架】MVVM的WPF框架(一)—序篇
前言我想,有一部分程序员应该是在二三线城市的,虽然不知道占比,但想来应该不在少数。 我是这部分人群中的一份子。 我们这群人,面对的客户,大多是国内中小企业,或者政府的小部门。这类客户的特点是,资金有限,人力有限。
1524 0

热门文章

最新文章