显示具有 Data-Binding 标签的文章。 显示所有文章
显示具有 Data-Binding 标签的文章。 显示所有文章

2008年6月27日 星期五

Flex 技巧 - 将资料绑定封装起来   [+/-]

Ticore's Blog

之前介绍了 纯手工设置 Flex DataBinding 的方式
不过那挺麻烦的
假如想要将 DataBinding 封装起来,保留部分弹性
又不想要那么麻烦的设置方式
不妨可以试试看以下的方式

在这个例子中,完全的将 DataBinding 封装在一个 MXML Component 中
必须要指定好目标物,Component 内的 DataBinding 才会发生作用
想要停止 DataBinding 也很简单,只要将目标属性设为 null 就好

甚至可以对一份资料,准备多个 DataBinding Component
只要在运行期动态替换 Component,就能达到切换 DataBinding 行为的目的
其实还挺方便的

Main.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  verticalAlign="middle" backgroundColor="#FFFFFF"
  creationComplete="init();" fontSize="12">
 <mx:Script>
  <![CDATA[
   public var comp:BindingComp;
   
   public function init():void{
    comp = new BindingComp();
    comp.initialize();
   }
  ]]>
 </mx:Script>
 <mx:HBox>
  <mx:Label text="No 1:" />
  <mx:NumericStepper id="no1" maximum="100" />
 </mx:HBox>
 <mx:HBox>
  <mx:Label text="No 2:" />
  <mx:NumericStepper id="no2" maximum="100" />
 </mx:HBox>
 <mx:CheckBox id="chk" label="DataBinding Enabled"
   change="comp.target = chk.selected ? this : null;" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

BindingComp.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:UIComponent xmlns:mx="http://www.adobe.com/2006/mxml">
 <mx:Script>
  <![CDATA[
   [Bindable]
   public var target:Main;
   
   public function doBinding1(... args:*):void{
    if (target) target.no2.value = target.no1.value;
   }
   public function doBinding2(... args:*):void{
    if (target) target.no1.value = target.no2.value;
   }
  ]]>
 </mx:Script>
 <mx:Model>
  {doBinding1(target.no1.value)}
 </mx:Model>
 <mx:Model>
  {doBinding2(target.no2.value)}
 </mx:Model>
</mx:UIComponent>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

线上测试示范:

相关连结:
Flex - 纯手工设置 DataBinding 的方式
Flex 技巧 - BindingManager 使用方式
Flex 技巧 - 观察 Data Binding 资料变化
Flex Tip - 在 Data Binding 内使用 [...] 运算子
Flex 2 Bindable Metadata Tag 背后实际作用
Flex 2.0 - 以 ActionScript 3.0 动态设置 Data Binding

Read more...

2008年6月10日 星期二

Flex - 纯手工设置 DataBinding 的方式   [+/-]

Ticore's Blog

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/ -->

步骤有点多~~

  1. 实作 mx.binding.IBindingClient; 界面

  2. 汇入必要的 Class:

    import mx.binding.*;
    import mx.binding.utils.*;
    import mx.core.mx_internal;
    

  3. 宣告 Bindings, Watchers 等属性:

    mx_internal var _bindings : Array = [];
    mx_internal var _watchers : Array = [];
    mx_internal var _bindingsByDestination : Object = {};
    mx_internal var _bindingsBeginWithWord : Object = {};
    

  4. 创建 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

Read more...

2008年6月8日 星期日

Flex 技巧 - BindingManager 使用方式   [+/-]

Ticore's Blog

Flex 的 mx.binding.*; 内有许多未公开的类别
主要都是给 MXML Compiler 使用的
其中 mx.binding.BindingManager 便是负责管理所有的 DataBinding 运作
BindingManager 内有一些静态函式还蛮有用的
列举如下:

  • BindingManager.setEnabled(document:Object, isEnabled:Boolean):void;
    用来 停止/启动 Flex Application/Component 内 Data Binding

  • BindingManager.executeBindings(document:Object, destStr:String, destObj:Object):void;
    运行被指定 Data Binding Expression

  • BindingManager.debugBinding(destinationString:String):void;
    对指定的 Data Binding Expression 进行除错

以下是简单的 BindingManager 使用示范程序:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" layout="vertical" fontSize="12"
   creationComplete="onCreateComplete();">
  <mx:Script>
   <![CDATA[
    import mx.binding.*;
    public function onCreateComplete():void{
     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" value="{slider1.value}" />
  
  <mx:CheckBox id="chk" label="Binding Enabled" selected="true"
    change="BindingManager.setEnabled(this, chk.selected); btn.enabled = chk.selected;" />
    
  <mx:Button id="btn" label="Execute DataBinding"
    click="BindingManager.executeBindings(this, 'slider2.value', null);" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

测试输出结果:

Binding: destString = slider2.value, srcFunc result = 54
Binding: destString = slider2.value, srcFunc result = 59
Binding: destString = slider2.value, srcFunc result = 81
Binding: destString = slider2.value, srcFunc result = 41

相关连结:
Flex 技巧 - 将资料绑定封装起来
Flex - 纯手工设置 DataBinding 的方式
Flex 技巧 - 观察 Data Binding 资料变化
Flex Tip - 在 Data Binding 内使用 [...] 运算子
Flex 2 Bindable Metadata Tag 背后实际作用
Flex 2.0 - 以 ActionScript 3.0 动态设置 Data Binding

Read more...

2008年6月6日 星期五

Flex 技巧 - 观察 Data Binding 资料变化   [+/-]

Ticore's Blog

Flex Data Binding 功能让开发者不用写太多的程序码
就能做到资料系结功能
但是要除错的时候就比较不太方便
Data Binding Expression 区块内很多语法都不能使用
当 Data Binding 被触发时,想要观察资料变化就不太方便

以下分享一个小技巧,可以很简单的观察 Data Binding 前后资料的变化

<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" />

  <mx:Label text="Binding Destination:" />
  <mx:HSlider id="slider2" snapInterval="1" maximum="100"
    value="{trace('Before :', slider2.value),
    setTimeout(function():void{trace('After :', slider2.value);}, 0), slider1.value}"/>
  
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

由于 Data Binding Expression 内不能使用 ";" 结尾的陈述式
所以使用 "," 作区隔,只有最后一个 Expression 会被当作值指定给目标
这样在前面就可以 trace 到变化之前的值
配合 setTimeout 又可以观察到变化之后的值

相关连结:
Flex 技巧 - 将资料绑定封装起来
Flex - 纯手工设置 DataBinding 的方式
Flex 技巧 - BindingManager 使用方式
Flex Tip - 在 Data Binding 内使用 [...] 运算子
Flex 2 Bindable Metadata Tag 背后实际作用
Flex 2.0 - 以 ActionScript 3.0 动态设置 Data Binding

Read more...

2008年3月25日 星期二

Flex ListBase selectedIndices, selectedItems Bug   [+/-]

Ticore's Blog

Flex ListBase, AdvancedListBase 有一个很严重的 Bug
只要是继承 ListBase, AdvancedListBase 的组件都会受到影响
像是 List, Menu, Tree, DataGrid, HorizontalList, TileList
与 AdvancedDataGrid, OLAPDataGrid

selectedIndices, selectedItems Bug 描述:

  • 当 dataProvider 内没有资料时,指定 selectedIndices 为空数组 []
    会造成往后取用 selectedIndices 永远得到空数组

  • 当 dataProvider 内没有资料时,指定 selectedItems 为空数组 []
    会造成往后取用 selectedItems 永远得到空数组

以上的 Bug 在 Flex SDK 2.0.1, 3.0 都会发生

ListBase selectedIndices, selectedItems Bug Demo Code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" fontSize="12"
  layout="vertical" verticalAlign="middle" backgroundColor="#F0F0F0">
 <mx:Style>
  Button {
   fontWeight: normal;
  }
 </mx:Style>
 <mx:Script>
  <![CDATA[
   import mx.collections.ArrayCollection;
   import mx.utils.ObjectUtil;
   
   [Bindable]
   public var itemData:ArrayCollection = new ArrayCollection();
   
   public function addItems():void{
    var num:Number = Math.random() * 20 + 3;
    for (var i:Number = 0 ; i < num ; i ++) {
     itemData.addItem({label: i});
    }
   }
   
   public function removeAllItems():void{
    itemData.removeAll();
   }
  ]]>
 </mx:Script>
 <mx:HBox>
  <mx:Label text="list.selectedIndices.length : {list.selectedIndices.length}" />
  <mx:Label text="list.selectedItems.length : {list.selectedItems.length}" />
 </mx:HBox>
 <mx:HRule width="100%" />
 <mx:HBox>
  <mx:List id="list" width="100" dataProvider="{itemData}" />
  <mx:VRule height="100%" />
  <mx:VBox>
   <mx:Button label="Add Items" click="addItems()" />
   <mx:Button label="Remove All  Items" click="removeAllItems()" />
   <mx:HRule width="100%"/>
   <mx:Button label="selectedIndices = []" click="list.selectedIndices = []" />
   <mx:Button label="selectedItems = []" click="list.selectedItems = []" />
   <mx:HRule width="100%"/>
   <mx:Button label="selectedIndex = -1" click="list.selectedIndex = -1" />
   <mx:Button label="selectedItem = null" click="list.selectedItem = null" />
  </mx:VBox>
  <mx:VRule height="100%" />
  <mx:VBox>
   <mx:Button label="trace(list.selectedIndices);"
     click="trace(ObjectUtil.toString(list.selectedIndices));" />
   <mx:Button label="trace(list.selectedItems);"
     click="trace(ObjectUtil.toString(list.selectedItems));" />
   <mx:Button label="trace(list.selectedIndex);"
     click="trace(list.selectedIndex);" />
  </mx:VBox>
 </mx:HBox>
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

只要在 List 没有资料情况下,点一下 "selectedIndices = []", selectedItems = []" 按钮
之后再按 "Add Items" 添加资料,点选 List 内的 Item
就会发现 selectedIndices, selectedItems 长度永远是 0
无法撤消

追踪 ListBase 原始码
发现问题是出在 bSelectedIndicesChanged, bSelectedItemsChanged
ListBase 内唯一将这两个变量设回 false 动作是发生在 adjustSelectionSettings 函式内

...
if (bSelectedIndicesChanged
    && (collectionHasItems || (_selectedIndices == null)))
{
    bSelectedIndicesChanged = false;
    bSelectedIndexChanged = false;
    commitSelectedIndices(_selectedIndices);
}

if (bSelectedItemsChanged
    && (collectionHasItems || (_selectedItems == null)))
{
    bSelectedItemsChanged = false;
    bSelectedIndexChanged = false;
    commitSelectedItems(_selectedItems);
}
...

但是 _selectedItems 根本不可能为 null
导致这两个旗标没有办法正常的被设回 false....

解决方式,只好自行继承 List 等相关组件
于设置 selectedIndices, selectedItems 时检查了

package com.ticore.uicomponents {
 import mx.controls.List;

 public class MyList extends List {
  public function MyList() {
   super();
  }
  
  [Bindable("change")]
  [Bindable("valueCommit")]
  [Inspectable(category="General")]
  public override function get selectedIndices():Array {
   return super.selectedIndices;
  }
  public override function set selectedIndices(indices:Array):void{
   if (this.collection && this.collection.length > 0) {
    super.selectedIndices = indices;
   }
  }
   
  [Bindable("change")]
  [Bindable("valueCommit")]
  [Inspectable(environment="none")]
  public override function get selectedItems():Array {
   return super.selectedItems;
  }
  public override function set selectedItems(items:Array):void{
   if (this.collection && this.collection.length > 0) {
    super.selectedItems = items;
   }
  }
   
 }
}

相关连结:
Flex ListBase selectedItems, selectedIndices 陷阱

Read more...

2008年3月20日 星期四

Flex Tip - 在 Data Binding 内使用 [...] 运算子   [+/-]

Ticore's Blog

Flex MXML 的 Data Binding 功能很好用
但是在 Expression 区块内使用关联数组访问运算子会出现警告

Data binding will not be able to detect changes when using square bracket operator.
For Array, please use ArrayCollection.getItemAt() instead.

这是由于 Data Binding 无法检测到 Array 内元素的改变而跳出的警告消息
依照它的建议,改用 ArrayCollection.getItemAt() 可以解决
但是,很多情况下,资料来源并不是数组啊

以下便是一个例子
资料来源是 ObjectProxy 对象
objectProxy 对象整个被替换时,与 cb.value 改变时
Data Binding 都会被正常触发
objectProxy.prop1 属性单独改变时则不会触发
有时候,我们只需要这样的功能
但是它仍然会出现警告消息

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#F0F0F0" layout="vertical">
    <mx:Script>
        <![CDATA[
         import mx.utils.ObjectProxy;
         import mx.controls.*;
   
         [Bindable]
         public var objectProxy:ObjectProxy =
           new ObjectProxy({prop1: "Prop 1", prop2: "Prop 2", prop3: "Prop 3"});
        ]]>
    </mx:Script>
 <mx:ComboBox id="cb" dataProvider="[1, 2, 3]" />
 <mx:Label text="{objectProxy['prop' + cb.value]}" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

这个时候,就面临两难了
是要放弃好用的 Data Binding Expression? 或是对警告消息视而无见?

解决方式 1. 利用匿名函式将关联数组访问运算子包起来

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#F0F0F0" layout="vertical">
    <mx:Script>
        <![CDATA[
         import mx.utils.ObjectProxy;
         import mx.controls.*;
   
         [Bindable]
         public var objectProxy:ObjectProxy =
           new ObjectProxy({prop1: "Prop 1", prop2: "Prop 2", prop3: "Prop 3"});
        ]]>
    </mx:Script>
 <mx:ComboBox id="cb" dataProvider="[1, 2, 3]" />
 <mx:Label text="{(function():*{return objectProxy['prop' + cb.value];})(objectProxy, cb.value)}" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

解决方式 2. 将关联数组访问运算子放到外部函式

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#F0F0F0" layout="vertical">
    <mx:Script>
        <![CDATA[
         import mx.utils.ObjectProxy;
         import mx.controls.*;
   
         [Bindable]
         public var objectProxy:ObjectProxy =
           new ObjectProxy({prop1: "Prop 1", prop2: "Prop 2", prop3: "Prop 3"});
         
         public function getProp(...args):*{
          return objectProxy['prop' + cb.value];
         }
        ]]>
    </mx:Script>
 <mx:ComboBox id="cb" dataProvider="[1, 2, 3]" />
 <mx:Label text="{getProp(objectProxy, cb.value)}" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

重点来了,以上两种方法都有一个共通的要点
那就是 objectProxy, cb.value 这两个属性都要在 Data Binding Expression 内曝光一下
这样 Data Binding 才会抓到资料改变的触发事件

相关连结:
Flex 技巧 - 将资料绑定封装起来
Flex - 纯手工设置 DataBinding 的方式
Flex 技巧 - BindingManager 使用方式
Flex 技巧 - 观察 Data Binding 资料变化
Flex 2 Bindable Metadata Tag 背后实际作用
Flex 2.0 - 以 ActionScript 3.0 动态设置 Data Binding

Read more...

Flex 小技巧 - 让 List.selectedIndex 默认值为 0   [+/-]

Ticore's Blog

在使用 Flex List 或是其它具有 selectIndex 的组件时
常常会需要让 List 默认自动选到第一个 Item

不过当 List.dataProvider 资料来源变更时
之前设置好的 selectedIndex 又会被清除掉
假如企图在资料来源变更事件中主动设置 List.selectedIndex 也是没有作用的
因为 List 需要一点时间套用新的资料
这个时间差并不好抓
使用 callLater 也无法保证 100% 一定可行

以下分享一个小技巧
可以让 List 每次资料变更后,就自动默认选定第一个 Item 上

使用方式很简单,让 selectedIndex 自己绑定自己就好了

Flex MXML Code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#F0F0F0" layout="vertical">
    <mx:Script>
        <![CDATA[
   import mx.controls.*;
   
   [Bindable]
   public var listData:Array = [];
   
   public function doUpdateData():void{
    listData = [];
    for (var i:Number = 0 ; i < 16 ; ++i) {
     listData.push(Math.round(Math.random() * 10000));
    }
   }
        ]]>
    </mx:Script>
 <mx:List id="list" width="100" height="200" dataProvider="{listData}"
   selectedIndex="{list.selectedIndex &lt; 0 ? 0 : list.selectedIndex}" />
 <mx:Button label="Update Data" click="doUpdateData()" />
</mx:Application>
<!-- Ticore's BLog - http://ticore.blogspot.com/ -->
Read more...

2007年1月14日 星期日

Flex 2 Bindable Metadata Tag 背后实际作用   [+/-]

Ticore's Blog

Flex 有一个很方便的功能 - Data Bind
很容易可以做到资料绑定的功能

对于 AS3 Class 加上 [Bindable] metadata tag
便可以对该 Class 资料成员赋予 Data Bind 能力

以下利用 flash.utils.describeType 观察 Bindable 对 Class 实际的影响

加上 [Bindable] 之前:

package idv.ticore {
 public class MyClass {
  public var name:String;
 }
}

describeType(MyClass) output:

<type name="idv.ticore::MyClass" base="Class" isDynamic="true" isFinal="true" isStatic="true">
  <extendsClass type="Class"/>
  <extendsClass type="Object"/>
  <accessor name="prototype" access="readonly" type="*" declaredBy="Class"/>
  <factory type="idv.ticore::MyClass">
    <extendsClass type="Object"/>
    <variable name="name" type="String"/>
  </factory>
</type>

加上 [Bindable] 之后:

package idv.ticore {
 [Bindable]
 public class MyClass {
  public var name:String;
 }
}

describeType(MyClass) output:

<type name="idv.ticore::MyClass" base="Class" isDynamic="true" isFinal="true" isStatic="true">
  <extendsClass type="Class"/>
  <extendsClass type="Object"/>
  <accessor name="prototype" access="readonly" type="*" declaredBy="Class"/>
  <factory type="idv.ticore::MyClass">
    <extendsClass type="Object"/>
    <implementsInterface type="flash.events::IEventDispatcher"/>
    <accessor name="name" access="readwrite" type="String" declaredBy="idv.ticore::MyClass">
      <metadata name="Bindable">
        <arg key="event" value="propertyChange"/>
      </metadata>
    </accessor>
    <method name="addEventListener" declaredBy="idv.ticore::MyClass" returnType="void">
      <parameter index="1" type="String" optional="false"/>
      <parameter index="2" type="Function" optional="false"/>
      <parameter index="3" type="Boolean" optional="true"/>
      <parameter index="4" type="int" optional="true"/>
      <parameter index="5" type="Boolean" optional="true"/>
    </method>
    <method name="hasEventListener" declaredBy="idv.ticore::MyClass" returnType="Boolean">
      <parameter index="1" type="String" optional="false"/>
    </method>
    <method name="willTrigger" declaredBy="idv.ticore::MyClass" returnType="Boolean">
      <parameter index="1" type="String" optional="false"/>
    </method>
    <method name="dispatchEvent" declaredBy="idv.ticore::MyClass" returnType="Boolean">
      <parameter index="1" type="flash.events::Event" optional="false"/>
    </method>
    <method name="removeEventListener" declaredBy="idv.ticore::MyClass" returnType="void">
      <parameter index="1" type="String" optional="false"/>
      <parameter index="2" type="Function" optional="false"/>
      <parameter index="3" type="Boolean" optional="true"/>
    </method>
  </factory>
</type>

可以发现在编译过程中,MyClass 自动实做了 flash.events::IEventDispatcher 界面
添加了四个与事件有关的方法
原本简单的资料成员的宣告方式
也被改成 getter、setter 的写法
是用来处理发布属性改变的事件

假如在一般 ActionScript3 Project 下使用 [Bindable]
则会出现错误消息

Severity and Description Path Resource Location Creation Time Id

  1172: Definition mx.binding:BindingManager could not be found. BindableTest/idv/ticore MyClass.as line 1 1168754444078 138
  1172: Definition mx.binding:BindingManager could not be found. BindableTest/idv/ticore MyClass.as line 1 1168754444078 143
  1172: Definition mx.core:IPropertyChangeNotifier could not be found. BindableTest/idv/ticore MyClass.as line 1 1168754444078 137
  1172: Definition mx.core:IPropertyChangeNotifier could not be found. BindableTest/idv/ticore MyClass.as line 1 1168754444078 142
  1172: Definition mx.events:PropertyChangeEvent could not be found. BindableTest/idv/ticore MyClass.as line 1 1168754444078 139
  1172: Definition mx.events:PropertyChangeEvent could not be found. BindableTest/idv/ticore MyClass.as line 1 1168754444078 144
  1172: Definition mx.utils:ObjectProxy could not be found. BindableTest/idv/ticore MyClass.as line 1 1168754444078 136
  1172: Definition mx.utils:ObjectProxy could not be found. BindableTest/idv/ticore MyClass.as line 1 1168754444078 141
  1172: Definition mx.utils:UIDUtil could not be found. BindableTest/idv/ticore MyClass.as line 1 1168754444062 135
  1172: Definition mx.utils:UIDUtil could not be found. BindableTest/idv/ticore MyClass.as line 1 1168754444078 140
  1202: Access of undefined property PropertyChangeEvent in package mx.events. BindableTest/idv/ticore MyClass.as line 4 1168754444078 145

因为缺少 Data Bind 中需要用到的 Class

只要添加 framework library 即可
framework 路径:${FRAMEWORKS}libsframework.swc

Flex 线上文档:
Using static properties as the source for data binding

相关连结:
Flex 技巧 - 将资料绑定封装起来
Flex - 纯手工设置 DataBinding 的方式
Flex 技巧 - BindingManager 使用方式
Flex 技巧 - 观察 Data Binding 资料变化
Flex Tip - 在 Data Binding 内使用 [...] 运算子
Flex 2.0 - 以 ActionScript 3.0 动态设置 Data Binding

Read more...

2006年12月2日 星期六

Flex 2.0 - 以 ActionScript 3.0 动态设置 Data Binding   [+/-]

Ticore's Blog

Flex 有一个很好用的 DataBinding 的功能
只要在 MXML 中使用大括号以点语法指定来源资料

像这样

<mx:textinput id="txt1">
<mx:textinput text="{txt1.text}" id="txt2" /></mx:textinput>

即可轻松创建资料系结

其它可以参考官方文档 Flex 2 - Binding Data

若想要用动态创建 Data Binding,或是动态改变系结属性
文档上却没有详细相关资料

在 Flex 2.0 Language Reference 里面
有两个 Class 与 Data Binding 有关

mx.binding.utils.BindingUtils
mx.binding.utils.ChangeWatcher

不过没有使用示范

以下示范使用这两个 Class 动态创建 Data Binding

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="init();">
 <mx:Script>
  <![CDATA[

    import mx.binding.utils.*;
    public var watcher:ChangeWatcher;
    public function init():void{
      watcher = BindingUtils.bindProperty(txt2, "text", txt1, ["text"], true);
    }

  ]]>
 </mx:Script>
 <mx:TextInput id="txt1" />
 <mx:TextInput id="txt2" />
 <mx:TextInput id="txt3" />
</mx:Application>

这样就可以创建单向 txt1.text 到 txt2.text 的 Data Binding

其它相关的操作方式

※停止资料系结

watcher.unwatch();

※系结到其它对象

watcher.reset(txt3);

※更改目标对象

watcher.setHandler(
 function(event:*):void{
  txt3["text"] = watcher.getValue();
 }
);

相关连结:
Flex 技巧 - 将资料绑定封装起来
Flex - 纯手工设置 DataBinding 的方式
Flex 技巧 - BindingManager 使用方式
Flex 技巧 - 观察 Data Binding 资料变化
Flex Tip - 在 Data Binding 内使用 [...] 运算子
Flex 2 Bindable Metadata Tag 背后实际作用

Read more...