Flex 的 DataBinding Expression 功能雖然非常方便
不用自行呼叫 addEventListener,省去了不少程式碼
但是換個角度看,Flex DataBinding 其實是有點缺乏彈性
不用自行加入監聽事件,同時也意味著不能移除監聽事件
然而,自行利用 addEventListener 方式實作的 DataBinding
感覺好像又沒有 Flex Compiler 產生的好~
於是想要觀察 Flex Compiler 產生的程式碼
進而自行模仿實作 DataBinding
想要觀察 Flex Compiler 產生的 ActionScript 很簡單
只要加入編譯參數 -keep-generated-actionscript=true
就可以在 /src/generated 下找到了
舉例來說,想要模擬以下的 DataBinding Expression:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundColor="#FFFFFF" layout="vertical" fontSize="12">
<mx:Label text="Binding Source:" />
<mx:HSlider id="slider1" snapInterval="1" maximum="100" value="50" />
<mx:Label text="Binding Destination:" />
<mx:HSlider id="slider2" snapInterval="1" maximum="100" value="{slider1.value}" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->
步驟有點多~~
-
實作
mx.binding.IBindingClient;介面 -
匯入必要的 Class:
import mx.binding.*; import mx.binding.utils.*; import mx.core.mx_internal;
-
宣告 Bindings, Watchers 等屬性:
mx_internal var _bindings : Array = []; mx_internal var _watchers : Array = []; mx_internal var _bindingsByDestination : Object = {}; mx_internal var _bindingsBeginWithWord : Object = {}; -
建立 Bindings 與 Watchers:
mx_internal::_bindings[0] = new Binding(this, function():* {return slider1.value;}, function(sourceReturnValue:*):void {slider2.value = sourceReturnValue;}, "slider2.value"); mx_internal::_watchers[0] = new PropertyWatcher("slider1", {propertyChange: true}, [mx_internal::_bindings[0]], function(propertyName:String):* { return this[propertyName]; }); mx_internal::_watchers[1] = new PropertyWatcher("value", {valueCommit: true, change: true}, [mx_internal::_bindings[0]], null); mx_internal::_watchers[0].updateParent(this); mx_internal::_watchers[0].addChild(mx_internal::_watchers[1]); mx_internal::_bindings[0].execute();
最後一個步驟看起來就有點複雜了
Binding 的功能有點類似 Event Handler,負責執行 DataBinding 運算
而 Watcher 則是類似 Event Listener,負責監聽資料來源的變化
為什麼不用標準的 Event Listener 機制
看 Flex Source 上寫的是因為效能考量
先看一下 mx.binding.Binding 類別的使用方式
public function Binding(document:Object, srcFunc:Function, destFunc:Function, destString:String)
- document: binding 目標的文件
- srcFunc: 用來取值的函式
- destFunc: 將值指定到目的地的函式
- destString: 用來告訴 ValidationManager 驗證該欄位
至於 Watcher 其實只是一個上層類別
實際使用時,需要視 Binding Source 種類決定使用哪一種子 Watcher
XMLWatcher, PropertyWatcher, StaticPropertyWatcher, RepeaterItemWatcher, RepeaterComponentWatcher,
FunctionReturnWatcher, ArrayElementWatcher
Watcher 有一個最特別的地方是,它具有父子關係
上層的父 Watcher 會觸發下層的子 Watcher 物件
可以藉由以下 Watcher 函式設定:
public function updateParent(parent:Object):void; public function addChild(child:Watcher):void; public function removeChildren(startingIndex:int):void; public function updateChildren():void;
綜合上述的步驟
完整手工設定的 DataBinding MXML 程式碼如下:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundColor="#FFFFFF" layout="vertical" fontSize="12"
implements="mx.binding.IBindingClient"
creationComplete="onCreateComplete();">
<mx:Script>
<![CDATA[
import mx.binding.*;
import mx.binding.utils.*;
import mx.core.mx_internal;
mx_internal var _bindings : Array = [];
mx_internal var _watchers : Array = [];
mx_internal var _bindingsByDestination : Object = {};
mx_internal var _bindingsBeginWithWord : Object = {};
public function onCreateComplete():void{
mx_internal::_bindings[0] = new Binding(this,
function():* {return slider1.value;},
function(sourceReturnValue:*):void {slider2.value = sourceReturnValue;},
"slider2.value");
// mx_internal::_bindings[0].mx_internal::isEnabled = false;
mx_internal::_watchers[0] = new PropertyWatcher("slider1",
{propertyChange: true},
[mx_internal::_bindings[0]],
function(propertyName:String):* { return this[propertyName]; });
mx_internal::_watchers[1] = new PropertyWatcher("value",
{valueCommit: true, change: true},
[mx_internal::_bindings[0]], null);
mx_internal::_watchers[0].updateParent(this);
mx_internal::_watchers[0].addChild(mx_internal::_watchers[1]);
mx_internal::_bindings[0].execute();
// BindingManager.debugBinding("slider2.value");
}
]]>
</mx:Script>
<mx:Label text="Binding Source:" />
<mx:HSlider id="slider1" snapInterval="1" maximum="100" value="50" />
<mx:Label text="Binding Destination:" />
<mx:HSlider id="slider2" snapInterval="1" maximum="100" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->
相關連結:
Flex 技巧 - 將資料綁定封裝起來
Flex 技巧 - BindingManager 使用方式
Flex 技巧 - 觀察 Data Binding 資料變化
Flex Tip - 在 Data Binding 內使用 [...] 運算子
Flex 2 Bindable Metadata Tag 背後實際作用
Flex 2.0 - 以 ActionScript 3.0 動態設置 Data Binding
Soph-Ware Associates Blog - Data Binding in Flex, Part I
Soph-Ware Associates Blog - Data Binding in Flex, Part II



0 意見 :
張貼意見