快捷搜索:

使用 Castal DynamicProxy 简化 Silverlight 数据绑定

大年夜家都知道, 在应用 Silverlight 数据绑定的时刻, 为了使源工具的变动能够传播到目标,源必须实现 INotifyPropertyChanged 接口。INotifyPropertyChanged 具有 PropertyChanged 事故,该事故看护绑定引擎源已变动,以便绑定引擎可以更新目标值。

下面是一个范例的例子:

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 接口,代码如下:

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 事故, 拦截器代码如下:

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 的代码如下:

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 终极的代码如下:

public class UserModel : BaseModel {

public virtual string FirstName {

get;

set;

}

public virtual string LastName {

get;

set;

}

}

着末,应用 UserModel 的代码是这样的:

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 数据绑定也很适用。

您可能还会对下面的文章感兴趣: