还是比较喜欢ASP.NET AJAX早期版本中出现的xml绑定技术,这部分功能在正式版中虽然被移除了,但是在微软放出的CTP版本中依然存在,而且内部结构发生了很大的变化,唯一庆幸的是xml绑定的语法基本上没有变化,所以一直在研究这个版本。
首先说一下这个版本的优点,给我感觉最好的就是兼容主流浏览器,我用IE7、FireFox1.5.10和Opera9.10测试过,xml绑定都能够正常工作,看来微软还是下了一番功夫的。
但是,在这个版本中,实现xml绑定的核心Sys.Preview.Binding类中有个致命的Bug,会导致在某些情况下绑定出错。先看一下Sys.Preview.Binding.initialize的源代码:
function Sys$Preview$Binding$initialize() {
Sys.Preview.Binding.callBaseMethod(this, 'initialize');
if (this.get_automatic()) {
if (this._direction !== Sys.Preview.BindingDirection.In) {
var target = this.get_target();
if (Sys.INotifyPropertyChange.isImplementedBy(target)) {
this._targetNotificationHandler = Function.createDelegate(this, this._onTargetPropertyChanged);
target.add_propertyChanged(this._targetNotificationHandler);
}
// 问题出现在这里,当direction不等于In,也就是Out或者InOut时,
// 当target死掉时通知绑定target已经死掉,
// 但是,如果Source死掉呢?怎么办?不知道。
if (Sys.INotifyDisposing.isImplementedBy(target)) {
this._targetDisposingHandler = Function.createDelegate(this, this._onDisposing);
target.add_disposing(this._targetDisposingHandler);
}
}
if (this._direction !== Sys.Preview.BindingDirection.Out) {
var source = this._getSource();
if (Sys.INotifyPropertyChange.isImplementedBy(source)) {
this._sourceNotificationHandler = Function.createDelegate(this, this._onSourcePropertyChanged);
source.add_propertyChanged(this._sourceNotificationHandler);
}
// 这里犯有同样的错误,当direction不等于Out,也就是In或者InOut时,
// source死掉时会通知绑定source已死,
// 但是却没有考虑让target死掉时也通知binding
if (Sys.INotifyDisposing.isImplementedBy(source)) {
this._sourceDisposingHandler = Function.createDelegate(this, this._onDisposing);
source.add_disposing(this._sourceDisposingHandler);
}
this.evaluate(Sys.Preview.BindingDirection.In);
}
}
}
既然是绑定,那个就应该不管是source还是target任意一方死掉时,都应该通知绑定,自己将死,让绑定做好善后工作,以上代码只要稍微修改一下,就可以正常工作了。
要改写这个方法,我们需要重写这个方法,修改好的代码如下:
Sys.Preview.Binding.prototype.initialize = function() {
Sys.Preview.Binding.callBaseMethod(this, 'initialize');
if (this.get_automatic()) {
var target = this.get_target();
var source = this._getSource();
if (this._direction !== Sys.Preview.BindingDirection.In) {
if (Sys.INotifyPropertyChange.isImplementedBy(target)) {
this._targetNotificationHandler = Function.createDelegate(this, this._onTargetPropertyChanged);
target.add_propertyChanged(this._targetNotificationHandler);
}
}
if (this._direction !== Sys.Preview.BindingDirection.Out) {
if (Sys.INotifyPropertyChange.isImplementedBy(source)) {
this._sourceNotificationHandler = Function.createDelegate(this, this._onSourcePropertyChanged);
source.add_propertyChanged(this._sourceNotificationHandler);
}
this.evaluate(Sys.Preview.BindingDirection.In);
}
// 不管绑定的方向,不管target和source那个死掉,都要通知绑定,做好善后工作。
if (Sys.INotifyDisposing.isImplementedBy(target)) {
this._targetDisposingHandler = Function.createDelegate(this, this._onDisposing);
target.add_disposing(this._targetDisposingHandler);
}
if (Sys.INotifyDisposing.isImplementedBy(source)) {
this._sourceDisposingHandler = Function.createDelegate(this, this._onDisposing);
source.add_disposing(this._sourceDisposingHandler);
}
}
}不知道我的理解是否正确,随后,我会附上一个Demo的项目,来演示这个Bug。