博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Atlas揭秘 —— 绑定(Binding)
阅读量:6542 次
发布时间:2019-06-24

本文共 4574 字,大约阅读时间需要 15 分钟。

English Version:

架构提供了一种比ASP.NET中数据绑定(data binding)强大得多的客户端绑定模型。这种模型异常灵活,甚至有些类似WPF(Windows Presentation Foundation)中的绑定模型。提供的绑定模型允许您将某对象的任意一个属性绑定到另外一个对象的任意一个属性上。它不单单可以应用于数据绑定,甚至可以将某个控件的样式绑定到另外一个控件上。这样使得在中将一切关联起来变成可能。

在这个帖子中,我将尝试分析一些实现代码来解释是如何完成Binding的。

首先让我们察看一小段应用 Binding的代码。这里将一个textbox的text属性和一个select list的selectedValue属性绑定起来。无论你改变其中的哪个,在另一个上面都会有立刻得到体现。

HTML和ASPX,定义textbox和select list。(注意必须声明一个ScriptManager服务器端对象,以引入必须的JavaScript文件。)

None.gif
<
atlas:ScriptManager 
ID
="ScriptManager1"
 runat
="server"
 
/>
None.gif
<
div
>
None.gif    Input an integer from 1 to 5.
<
br 
/>
None.gif    
<
input 
id
="myTextBox"
 type
="text"
 
/><
br 
/>
None.gif    Select an item.
<
br 
/>
None.gif    
<
select 
id
="mySelect"
>
None.gif        
<
option 
value
="1"
>
value 1
</
option
>
None.gif        
<
option 
value
="2"
>
value 2
</
option
>
None.gif        
<
option 
value
="3"
>
value 3
</
option
>
None.gif        
<
option 
value
="4"
>
value 4
</
option
>
None.gif        
<
option 
value
="5"
>
value 5
</
option
>
None.gif    
</
select
>
None.gif
</
div
>

 

脚本,将上面两个HTML控件“升级”成控件。

None.gif
<
page 
xmlns:script
="http://schemas.microsoft.com/xml-script/2005"
>
None.gif    
<
references
>
None.gif    
</
references
>
None.gif    
<
components
>
None.gif        
<
textBox 
id
="myTextBox"
>
None.gif            
<
bindings
>
None.gif                
<
binding 
dataContext
="mySelect"
 dataPath
="selectedValue"
 property
="text"
 direction
="InOut"
 
/>
None.gif            
</
bindings
>
None.gif        
</
textBox
>
None.gif        
<
select 
id
="mySelect"
 
/>
None.gif    
</
components
>
None.gif
</
page
>

 

如上所示,我们只需要书写一小段简单的代码即可实现需要的绑定功能。

是如何实现这些的呢?首先,需要有一种途径来监听绑定控件的绑定属性的变化(除非你不需要提供的自动绑定功能)。在.js中定义了一个名为Sys.INotifyPropertyChanged的接口,类似.NET中提供的一样。对象可以实现这个接口以期让别的对象监听到自己的属性值的变化。中所有组件的基类,Sys.Component,实现了这个接口。Sys.Component同样提供一个方法raisePropertyChanged(propertyName),这个方法应该在每个属性的setter中被调用以发出INotifyPropertyChanged.propertyChanged事件。

目前为止,我们可以看一下控件中textbox的具体实现。看看textbox中是如何在相应的HTML事件发出时同样发出propertyChanged事件的。

None.gif
var
 _text;
None.gif
var
 _changeHandler;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
this
.get_text 
=
 
function
() 
dot.gif
{
InBlock.gif    
return this.element.value;
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
this
.set_text 
=
 
function
(value) 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
if (this.element.value != value) dot.gif{
InBlock.gif        
this.element.value = value;
InBlock.gif        
this.raisePropertyChanged('text');
ExpandedSubBlockEnd.gif    }
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
this
.initialize 
=
 
function
() 
dot.gif
{
InBlock.gif    Sys.UI.TextBox.callBaseMethod(
this, 'initialize');
InBlock.gif    
InBlock.gif    _text 
= this.element.value;
InBlock.gif
InBlock.gif    _changeHandler 
= Function.createDelegate(thisthis._onChanged);
InBlock.gif    
this.element.attachEvent('onchange', _changeHandler);
InBlock.gif    
InBlock.gif    _keyPressHandler 
= Function.createDelegate(thisthis._onKeyPress);
InBlock.gif    
this.element.attachEvent('onkeypress', _keyPressHandler);
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
this
._onChanged 
=
 
function
() 
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
if (this.element.value != _text) dot.gif{
InBlock.gif        _text 
= this.element.value;
InBlock.gif        
this.raisePropertyChanged('text');
ExpandedSubBlockEnd.gif    }
ExpandedBlockEnd.gif}

 

可以看到,当text属性改变时,发出了propertyChanged事件,这就使绑定到这个属性成为可能。

而后的绑定模型捕获到了这个事件,再根据binding声明查找出与其相关的目的对象以及相应的属性,并调用这个属性的Setter来实现目的对象属性的变化。

 

如果源对象( source object )实现了 INotifyPropertyChanged 接口,并且改变的属性就是 dataPath 中指定的属性,同时 direction 设定为 In 或者 InOut , 绑定将通过分析
引入(
incoming
的 binding 来处理 propertyChanged 事件(参考下面将要介绍的 evaluateIn() 方法)。

类似的,如果目的对象(target object)实现了INotifyPropertyChanged接口,并且改变的属性就是property中指定的属性,同时direction 设定为Out或者InOut,绑定将通过分析流出(outgoing的binding来处理propertyChanged事件(参考下面将要介绍的evaluateOut()方法)。

 

接下来让我们察看 binding 实现代码中的的公有方法和属性来分析一下 绑定的核心实现。在这里没有必要列出涉及绑定的全部代码,如果您感兴趣,可以用关键词 Sys.BindingBase 和 Sys.Binding 在 .js 文件中进行搜索。首先是
Sys.BindingBase 提供的方法和属性。

 

  1. 属性automatic:指定当源对象的相应属性变化时(对于In和InOut),或者目的对象的相应属性变化时(对于Out和InOut),绑定是否将被自动执行。这个属性默认会被置为true。当然如果你需要完全控制绑定的开始时机时也可以设定为false。例如,某些情况下你决定在一个AJAX请求成功返回的时候才开始绑定数据源与显示控件,以确保显示控件真正绑定到了一些数据,这时你需要显示的调用binding的evaluate()方法以开始绑定。
  2. 属性dataContext:指定拥有待绑定属性的对象。如果不指定的话,Atlas binding将调用包含它的父控件的dataContext属性代替。控件可以通过返回设定的dataContext或是按照默认返回其父控件的dataContext来实现这个属性。例如,某个ListView控件可以在其创建ListView Item时设定它的dataContext为一个DataRow对象,以实现绑定。
  3. 属性dataPath:指定需要绑定的源对象的属性。Atlas binding还允许绑定一个嵌套的属性,类似:sourceObjectProperty.nestedProperty.nestedNestedProperty。源代码中可以看出Atlas能自动为你转化并运行这些代码。dataPath属性的默认值为空,也就是Atlas会绑定这个对象本身。
  4. 属性property:指定需要绑定的目标对象的属性。你应该总是指定这个属性,否则这个绑定就没有任何意义。
  5. 属性propertyKey:有时候我们可能需要绑定到某个对象的嵌套属性上。比如,如果需要绑定到style的属性color,我们可以指定property属性为style,并指定propertyKey属性为color。
  6. 属性transformerArgument:传递给Atlas transformer的参数,只有设定transform时才会用到。
  7. 事件transform:这个事件允许在绑定时指定一个transformer。当你需要在绑定的时候对数据做以处理时,transformer将会是个很好的选择。例如,如果你希望显示一个布尔值为Yes/No而不是默认的true/false,那么就应该使用一个自定义的transformer。Atlas同时提供了一些内建的transformer,例如Add,Multiply以及Compare等。
  8. 方法evaluateIn:处理引入的binding。如果direction属性设置成为In或者InOut,该方法将取得源对象的属性的值(根据binding中设定的dataContext以及dataPath属性),并调用目标对象相应属性的Setter。这也就是Atlas中实现binding的核心部分。  

Sys.Binding(也在.js中)中也有一些重要的方法/属性:

 

  1. 属性direction:指定希望监听的属性变化的方向。可以设定为InOut或者InOut。默认值为In。
  2. 方法evaluateOut:与基类中的方法evaluateIn类似,但是以相反的方向执行。当然,需要将directiton属性设定为Out或者InOut。
希望这些解释能够让您对 的“神奇的”绑定有一些更深入的理解。欢迎留言探讨。

PS:这篇文章中有些英文不知道应该如何用中文表示,希望能得到一些建议以及指正:

  1. evaluate,我翻译成“处理”,但文中还有“计算求值”的意思,这一点没有体现出来。
  2. incoming和outgoing,我翻译成“引入”和“流出”……觉得不是一般的别扭。
  3. transformer,没有翻译(实在不知道怎么说了)。
  4. getter和setter,没有翻译(一直都不知道怎么翻译)。
你可能感兴趣的文章
Qt下的OpenGL 编程(8)文字、FPS、动画
查看>>
Android开发入门系列
查看>>
文件删除封装,懒得以后再写了
查看>>
Linux 脚本之用户创建
查看>>
Mysql字段类型设计相关问题!
查看>>
Xshell 密钥登陆
查看>>
所见不为真--图片格式文件检测python
查看>>
分享几种常用的嵌入式Linux GUI及其特点—干货
查看>>
Confluence 6 "Duplicate Key" 相关问题解决
查看>>
第18章 使用MariaDB数据库管理系统
查看>>
浅谈MySQL的B树索引与索引优化
查看>>
【喜报】HCIE--PASS !最可怕的敌人,就是没有坚强的信念!
查看>>
想学前端,为什么不看这些书呢?
查看>>
记一次mapreduce读取不到输入文件的问题
查看>>
我的友情链接
查看>>
MariaDB集群Galera Cluster的研究与测试
查看>>
SONY控制键盘JX-11,EVI-D70P控制方案
查看>>
Spring AOP 之二:Pointcut注解表达式
查看>>
在普通台式机上搭建服务器虚拟化架构Esxi平台
查看>>
电话线路 30B+D 名词解释
查看>>