Flex数据绑定大全

来源:互联网 发布:旭旭宝宝 知乎 编辑:程序博客网 时间:2024/04/29 08:18

总结一下Flex中的一般的数据绑定的几种实现方法。

首先先讲一下啥叫绑定呢?说白了就是把两个或几个东西绑在一起,一个变化的时候其他的也得跟着他变。这就产生了动态的效果了。其实叫数据绑定,到不如叫自动刷新合适。

1、用“{}”来进行绑定

<mx:TextInput id="txtSource" />
<mx:Text    id="txtDestination"   text="{txtSource.text}"/>

如果希望双向绑定的话,可以这样

<mx:TextInput  id="{txtDestination.text}" />
<mx:Text   id="txtDestination"    text="{txtSource.text}"/>

在“{}”这中间,可以计算表达式、连接字符串、条件表达式、函数,反正大概就是可以一句话写下的代码都可以。、

连接字符串不用“+”,直接写在后面

<mx:TextInput id="txtSource" />
<mx:Text id="txtDestination" text="{Number(txtSource.text)*100}"/>

 

2、用<mx:Binding>标签

<mx:Binding source="Number(txtSource.text) * 100"   destination="txtDestination.text" />

<mx:TextInput id="txtSource" />
<mx:TextInput id="txtDestination"/>

如果希望双向绑定的话,<mx:Binding>标签中有个 twoWay 属性,可以设置true或false来选择单向的还是双向的。

 

3、使用ActionScript来进行数据绑定

使用类mx.binding.utils.BindingUtils来创建mx.binding.utils.ChangeWatcher对象

有两个方法,bindProperty 将公用属性(site Object 上的 prop)绑定到可绑定属性

                  bindSetter    将setter 函数(setter)绑定到可绑定属性

 

4、[Bindable]元数据标签

[Bindable]大概又是Flex用得最多的元数据了。刚开始用用确实好简单,效率真是没的说。不过这几天用着却碰到了些问题,我自己搜集了些资料,想着有必要在blog里总结一下吧。

啥是元数据(metadata)

首先要明白元数据不是语法的一部分,而是专门给编译器用的,说白了是告诉编译器做某些事情,学过java之类的应该知道。那Bindable来讲,它的作用是告诉 flex编译器,给某些某些东西建立绑定关系,flex编译器会在编译过程中给AS(flex编译器就是把mxml编译成as,再编译到swf,也可能直接编译倒swf,我这里假设有as这么个环节)加一点事件发生和处理之类的代码,由此绑定的关系便建立了,如果我们用纯粹as3代码来写也是可以实现的,就是太麻烦。

啥是绑定

知道继续跳过。举个例子:给下面的public变量加上[Bindable]

[Bindable]
public var name:String = "";

作为一个public变量,肯定既可以被赋值,也能赋值给别的变量。绑定的作用就是,当name改变的时候(被赋值了),可能通知其它被name影响(赋值给它们)的变量发生改变。这里的“可能”就需要编译器来判断,这就是为什么元数据是给编译器用的原因了。在mxml里用{}的语法的地方就是绑定的对象,比如label={xxx.name},当name变化,label也跟着变化。这样,我们只是很简单的改变了name的值,由于有绑定,界面上的label也跟着自动变化了,爽吧。

能用在哪里

纯[Bindable]标签只能用在三个地方: 变量 getter/setter。是不是public没有关系,private的就只能给自家用呗。用在Class上就是简单的给所有的public属性(包括变量,getter/setter,普通方法)加上[Bindable],可是一般的方法(除了getter和setter之外的方法都是一般的方法)不能用[Bindable]呀(后面会讲到怎么用在一般的方法上),于是一般就能看到flex给了个warning,直接无视。变量嘛就是上面讲的,很简单略掉。

用在只读,只写属性(getter/setter)上面

终于讲到关键地方了,因为getter和setter很像方法,用起来会有点不同。看看这个例子:

[Bindable]
private var content:Array = new Array();
[Bindable]
public function set _content(ct:String):void
{
       content = ct.split(SEP);
}
[Bindable]              
public function get _wholeText():String
{
       if(content.length == 0)
       {
              return "";
       }
       else
       {
              var _w:String = "";
              for(var i:int=0 ; i<content.length ; i++)
              {
                     _w += content[i] + "/r/n";
              }
              return _w;
       }
}

原来的设想是content绑定_wholeText,可它是不工作的。为什么?_wholeText太复杂了,被编译器排除在“可能”之外,编译器认为没有绑定关系,如果只是简单的return content,倒是可以的。原来为了降低复杂度和提高效率,系统对于复杂情况的getter会被忽略。如何解决?可以手动建立绑定,即[Bindable("eventName")]。把代码改成这样:

[Bindable]
private var content:Array = new Array();
[Bindable]
public function set _content(ct:String):void
{
       content = ct.split(SEP);
        this.dispatchEvent(new Event("_contectChanged"));//派发事件
}
[Bindable("_contectChanged")]              
public function get _wholeText():String
{
       if(content.length == 0)
       {
              return "";
       }
       else
       {
              var _w:String = "";
              for(var i:int=0 ; i<content.length ; i++)
              {
                     _w += content[i] + "/r/n";
              }
              return _w;
       }
}

这样就避免了编译器去自动识别。自己加上绑定关系,当_content被赋值,发出_contentChanged事件,通知所有被绑定的getter方法执行一遍。这也说明了,绑定不过是事件游戏而已,flex为用户隐藏了很多底层算法。

这也就是下面要讲的。。。


5、绑定到一个普通函数

利用[Bindable]元数据标签进行绑定其实等价与[Bindable(event="propertyChange")],Flex中的数据绑定的基础其实是一个基于事件的系统。默认的数据绑定的事件类型是分发到propertyChange事件。有时我们可以自定义一个时间类型,通过使用[Bindable]标签中的event属性。这样我们就可以对于一个类中的一般方法(非getter和setter方法)作为数据源进行绑定。

例子:

<fx:Script>
  <![CDATA[

   private var _fruit:String;
   private var _fruits:Array = ["Apple","Banana","Orange"];
   [Bindable]
   public var _label:String ="first";

   public function get fruit():String
   {
    return _fruit;
   }

   public function set fruit(value:String):void
   {
    _fruit = value;
    dispatchEvent(new Event("fruitChanged"));
   }

   private function initHandler():void{
    fruitCB.dataProvider = _fruits;
   }
   
   [Bindable(event="fruitChanged")]
   private function isOrangeChosen():Boolean{
    return _fruit == "Orange";
   }
   
   
   
  ]]>
 </fx:Script>
 
 <mx:Label text="select a fruit:"/>
 <mx:HBox>
  <mx:ComboBox id="fruitCB" change="{fruit = fruitCB.selectedLabel}" />
  <mx:Button label="Eat the orange." enabled="{isOrangeChosen()}" /> 
  <mx:Label text="{_label}" width="146"/>
  <mx:Button click="_label = 'second'"/> 
  
 </mx:HBox>