[原] flex绑定, 我真的懂了吗? - 第三部分:绑定表达式

[本文原创链接: http://www.smithfox.com/?e=115 , 转载请保留此声明, 谢谢!!]

用过Flex的同学肯定都用过MXML中的绑定表达式, 比如 <s:Label text="{somevalue}" /> , 就完成了将变量somevalue绑定到text的动作.

本文一开始会查看MXML绑定表达式, 编译器生成的AS3是什么样, 然后总结一下在绑定表达式上做一点小文章可以简化一些复杂绑定.

我先打开"-keep=true"编译选项, 以便可以查看编译器生成的AS3代码.

MXML代码如下:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark">
	
	<fx:Script>
		<![CDATA[
		[Bindable]
		private var aaa:int=3;
		]]>
	</fx:Script>
	<s:Label text="{aaa}" />
</s:Application>

我先不关心[Bindable], 这个不是本文重点, 只关心 text="{aaa}" 相关的最主要的代码.

如下:

    //binding mgmt
    private function _test2_bindingsSetup():Array
    {
        var result:Array = [];

        result[0] = new mx.binding.Binding(this,
            function():String
            {
                var result:* = (aaa);
                return (result == undefined ? null : String(result));
            },
            null,
            "_test2_Label1.text"
            );


        return result;
    }

上面代码只是完成整个绑定的其中一个函数而已, 但这个函数是唯一和 aaa 变量直接相关的函数. 我们可见编译器会为这个绑定表达式, 生成一个嵌入式函数(不知道官方是否是这样称谓的) 作为Binding的srcFunc, 在这个embed srcFunc 中会将aaa赋值给result, 然后返回result.

至此, 我得出了一个结论: 大括号绑定最核心的地方就是一个简单的赋值. 这个结论好象没有什么值高兴的, 猜也能猜得出. 哈哈! 但值得注意的是, 它将 aaa 用小括号括起来了, 看起来多此一举, 实际上这个很有讲头, 下面会说到.

接下来切入正题:

1. MXML的绑定表达式中, 写复杂一点的逻辑时需要注意特殊符号.

接着上面的例子, 现在增加需求: 只有aaa大于10的时候, 才显示Label.

我们可能会改写成:  <s:Label text="{aaa}" visible="{aaa>10}" /> , 你会发现编译器报错, 你可能会为了解决这个问题再写一个函数(我以前就是这么干的), 比如 

private fuction isGreateThanTen():Boolean{
return (aaa>10);
}

然后MXML绑定写成: <s:Label text="{aaa}" visible="{isGreateThanTen()}" />, 接着你会发现更多的问题来了.

还是看看compiler为什么会报错. 其实这个问题本质就是在MXML中, 大于, 小于, 逻辑与 都是XML的保留字, 所以必须要转义: 大于 应该写成 &gt; 小于 应该写成  &lt;  逻辑与 写成 &amp; 

所以上面的问题只要改成:  <s:Label text="{aaa}" visible="{aaa&gt;10}" /> 就可以了.

根据不同的需要, 我们还甚至可以写成  <s:Label text="{aaa}" visible="{aaa&gt;10 &amp&amp aaa&lt;20}" />

2. 绑定表达式的逗号很有用

这个我是看到了 Ticore's Blog 的两篇文章才知道的, 我后来查了一下这种表达式的Adboe官方解释,  如下:

第二,可以结合使用小括号和逗号运算符 (,) 来计算一系列表达式并返回最后一个表达式的结果,如下面的示例所示:

var a:int = 2; 
var b:int = 3; 
trace((a++, b++, a+b)); // 7

考虑到 Ticore's Blog不能正常访问, 我就摘录如下:

Flex 技巧 - 觀察 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/ -->

再看下面的一个我自己的例子

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark">
	<fx:Script>
		<![CDATA[
		//现假定这个类是 你不能改动的类, 比如是一个flex SDK的控件
		
		//这个是你想绑定的属性 aaa, 可是被定义为一个int类型, 所以在外部直接无法发现aaa的变化
		public var aaa:int = 3;

		//bbb是这个控件的另一个属性, 它是能被直接bind的
		[Bindable]
		public var bbb:int = 0;
		
		//而且我们可以确信, 这个控件每次aaa变化的, bbb也必然一起变化, 
                //而且aaa的变化在bbb变化之前发生
		private function changeValue():void {
			var tmpValue:int = Math.round(Math.random() * 100);
			aaa = tmpValue +1;
			bbb = tmpValue;
			trace("bbb="+bbb+",aaa="+aaa);
		}
		]]>
	</fx:Script>
	
	<!-- 我们只要这样写, 就可以忽略compiler警告, 实际已经做到绑定aaa了, 这个有点像aaa搭了bbb的顺风车的感觉 
	PropertyChange的事件是由bbb发出的, 但因为逗号表达式的原因, 最终返回的是aaa的值
	-->
	<s:Label text="{bbb,aaa}"/>
	<s:Button label="Change value" click="changeValue()" y="30" />
</s:Application>

根据实际情况, 还可以变化的应用, 比如见  Ticore's Blog 的另一篇文章: Flex 技巧 - 可綁定的 ArrayList,

考虑到他的Blog在墙后, 现摘录如下:

Flex 4 新增的 ArrayList 有点像是轻量级的 ArrayCollection也因此 ArrayList 内所有的属性与方法都不能作绑定(ArrayList 原代码没有Bindable Metadata 标签)有时候我们需要绑定,又不想改用 ArrayCollection, 以下分享一个小技巧,只要稍作改变就能绑定 ArrayList的 属性
首先,在 MXML 声明一个整数变量每当发生 ArrayList.collectionChange 时,就对该变量累加. 假如想绑定 ArrayList.length 属性,只要在绑定表达式前面加上一个刚才的整数变量,就象 <s:Label text="{changeFlag, data.length}" /> 

完整代码如下:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:s="library://ns.adobe.com/flex/spark"
  xmlns:mx="library://ns.adobe.com/flex/mx" fontSize="14">
 <fx:Declarations>
  <s:ArrayList id="data" collectionChange="changeFlag++;" />
  <fx:int id="changeFlag"/>
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   public function getTimeStr():String{
    var date:Date = new Date();
    var hh:* = ("0" + date.getHours()).substr(-2, 2);
    var mm:* = ("0" + date.getMinutes()).substr(-2, 2);
    var ss:* = ("0" + date.getSeconds()).substr(-2, 2);
    var ms:* = ("00" + date.getMilliseconds()).substr(-3, 3);
    return hh + ":" + mm + ":" + ss + "." + ms;
   }
  ]]>
 </fx:Script>
 <s:layout>
  <s:VerticalLayout verticalAlign="middle" horizontalAlign="center" />
 </s:layout>
 <mx:Form>
  <mx:FormItem label="Latest Change Time:">
   <s:Label text="{changeFlag, getTimeStr()}" />
  </mx:FormItem>
  <mx:FormItem label="ArrayList.getItemAt(0):">
   <s:Label text="{changeFlag, data.getItemAt(0).id}" />
  </mx:FormItem>
  <mx:FormItem label="ArrayList.getItemAt(1):">
   <s:Label text="{changeFlag, data.getItemAt(1).id}" />
  </mx:FormItem>
  <mx:FormItem label="ArrayList.length:">
   <s:Label text="{changeFlag, data.length}" />
  </mx:FormItem>
  <mx:FormItem label="Operations:" direction="horizontal">
   <s:Button label="Add Item" click="data.addItem({id: Math.random()})" />
   <s:Button label="Remove All" click="data.removeAll()" />
  </mx:FormItem>
 </mx:Form>
</s:Application>

[本文原创链接: http://www.smithfox.com/?e=115 , 转载请保留此声明, 谢谢!!]

smithfox | Friday 11 March 2011 at 1:49 pm | | UI        | Used tags: , ,

No comments

(optional field)
(optional field)
为阻止垃圾广告, 请在提交评论前, 回答一个简单问题(Please answer an simple question)
Remember personal info?
Notify
Small print: All html tags except <b> and <i> will be removed from your comment. You can make links by just typing the url or mail-address.