Adobe Flex 大师之路第13章 数据基础_Adobe Flex 大师之路第13章 数据基础试读-查字典图书网
查字典图书网
当前位置: 查字典 > 图书网 > web > Adobe Flex 大师之路 > 第13章 数据基础

Adobe Flex 大师之路——第13章 数据基础

13.1 MXML的数据模型 在Flex应用开发中,处理数据是非常核心的工作。MXML提供了简单的方式帮助开发者在客户端存储数据,而更复杂的应用则须要利用ActionScript类来定义数据模型。 13.1.1  <mx:Model> <mx:Model>适合描述树状层次结构的数据。<mx:Model>声明必须置于MXML主应用文件或MXML组件文件的根标签下。<mx:Model>数据模型示例的代码如代码13-1所示。 代码13-1:<mx:Model>数据模型示例 <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" verticalAlign="middle" backgroundColor="white">     <mx:Script>         <![CDATA[             import mx.controls.Alert;             private function showAuthor():void{                 mx.controls.Alert.show(bookModel.name +"的作者是:" +               bookModel.author.firstName + " "                                          + bookModel.author.lastName + "n"                                          + " 订购数量:" + bookModel.quantity);             }         ]]>     </mx:Script>     <mx:Model id="bookModel">         <book>             <author>                 <firstName>{txtFirstName.text}</firstName>                 <lastName>{txtLastName.text}</lastName>             </author>             <name>{txtName.text}</name>             <quantity>{quantity.value}</quantity>         </book>     </mx:Model>     <mx:Form width="288">         <mx:FormItem label="书名:">             <mx:TextInput id="txtName" />         </mx:FormItem>         <mx:FormItem label="作者:">             <mx:TextInput id="txtFirstName" />             <mx:TextInput id="txtLastName" />         </mx:FormItem>                <mx:FormItem label="订购数量">             <mx:NumericStepper id="quantity"/>         </mx:FormItem>         <mx:FormItem>             <mx:Button id="button1" label="显示" click="showAuthor()"/>         </mx:FormItem>           </mx:Form> </mx:Application> 在上述应用示例中,用户填写完图书信息,点击“显示”按钮后,结果如图13-1所示。 图13-1  <mx:Model>示例结果 在这个例子中,可以看到,<mx:Model>声明的数据模型,最终被编译为ActionScript对象,通过其id进行引用。<mx:Model>能够很好地存储树型结构数据,但也仅限于此。其存储的数据局限于标量数据,不支持对数据的进一步处理。 在复杂的应用中,我们更经常使用ActionScript代码定义数据模型类。 13.1.2  ActionScript的DTO DTO,全称Data Transfer Object(数据传输对象),也被称作Value Object(简称VO)。DTO实际上就是简单的ActionScript类,该类的全部意义在于描述对象实体数据模型、存储数据,并在应用内部不同模块及应用与服务器之间传递数据。 与<mx:Model>定义的数据模型相比,DTO的属性变量不仅仅是标量类型(例如int、String等),也可以是复杂类型。DTO也能内嵌业务逻辑(例如数据校验、格式化等)。 一般来说,DTO类代码的最佳实践是,将属性声明为私有变量,并使用getter和setter方法提供属性的读写接口,DTO示例代码如代码13-2所示: 代码13-2:DTO示例 package com.longfei.bookLabs.bookStore.model {     [Bindable]     public class Book     {         public var name:String;         public var price:Number;         private var _quantity:int;                 public function Book()         {         }                 //5本起订         public function set quantity(value:int):void         {             if (value>= 5) { _quantity = value; }             else { trace('不足起订数!'); }         }         public function get quantity():int         {             return _quantity;         }     } } 许多专家和文章建议将DTO或VO对象的属性变量设置为私有属性,并通过setter和getter访问器实现读写。但事实上,如果不须要对属性变量进行业务逻辑处理,例如校验或格式化,那么使用公共属性也不见得会带来什么坏处。 如果要在MXML中使用DTO对象,须要引入并实例化该类。可以使用MXML标签声明方式,也可以采用ActionScript代码声明并创建类实例。 如果使用MXML标签声明,须要定义指向DTO对象的命名空间,然后为该DTO对象设置id属性。 <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"  xmlns:vo="com.longfei.bookLabs.bookStore.model.*" >     <!―省略代码-->       <!--使用MXML标签声明DTO对象实例-->     <vo:Book id="tempBook"/>       <!―省略代码--> </mx:Application> 用ActionScript代码创建DTO类实例的代码如下: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"> <mx:Script>     <![CDATA[         import com.longfei.bookLabs.bookStore.model.*;         //ActionScript代码创建类实例         private var book:Book;         ]]>     </mx:Script> <!―省略代码--> </mx:Application> 13.2  深入解析数据绑定 数据绑定能帮助开发者快速地把应用界面与数据联系在一起,用户在应用界面上的操作,能够即时反应到绑定的数据上。 在本书前面章节的许多例子中,我们已经使用过数据绑定。数据绑定就是把数据源A和目标数据B关联在一起的过程,数据源A也许是属性变量、对象、方法,甚至是数组元素。使用MXML和ActionScript都能够实现数据绑定。 Flex数据绑定的背后是事件机制的应用。开发者使用不同方式(MXML或ActionScript)声明绑定的时候,即为绑定事件注册了事件侦听器,当数据源发生变化时,就会调度时间侦听器,实现数据绑定逻辑,默认的绑定逻辑就是将更新的数据复制到目标对象。 13.2.1  声明可绑定数据源――[Bindable]解析 数据绑定的数据源可以是属性变量、方法及ActionScript类对象实例。Flex通过元数据标签[Bindable]进行标识。标识为绑定数据源意味着当数据源变化时,能够调度事件,通知Flex更新目标数据。 Bindable元数据标签的签名如下: [Bindable] 或者 [Bindable(event=”eventName”)] 开发者一般忽略事件(event)名称,只使用[Bindable]标识可绑定数据源。这种情况下,Flex会默认地创建mx.events.PropertyChangeEvent类型事件,事件名为propertyChange。当数据绑定的数据源发生变化时,数据源会自动调度propertyChange事件,通知Flex将新值复制给目标数据。 如果在标识绑定时说明了事件,也就是说采用了[Bindable (event=”eventName”)]方式,开发者须要自己定义和调度事件。 我们依次说明如何声明属性、ActionScript类和方法作为可绑定的数据源。 声明可绑定属性 在属性变量定义之前,使用元数据标签[Bindable]声明属性可绑定。属性可以是公共属性、私有属性或被保护属性。声明如下: [Bindable] public var employee:Employee=new Employee(); [Bindable] private var acEmployees:ArrayCollection=new ArrayCollection(); 如上声明后,employee和acEmployees变量可作为绑定数据源。 对于使用getter和setter方法定义的属性变量,需要在get或set方法前声明[Bindable]。如代码13-3所示。 代码13-3:getter和setter的属性绑定声明 <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"  verticalAlign="middle" backgroundColor="white" creationComplete="init();">     <mx:Script>         <![CDATA[             private var _prop:String;             private function init():void{                 prop='bind was triggerd';             }             [Bindable]                        private function set prop(value:String ):void{                 //自定义代码                 _prop=value;             }             private function get prop():String{                 //自定义代码                 return _prop;             }                    ]]>     </mx:Script>     <mx:Text id="txtDest" text="{prop}"/>     <mx:Button label="修改" click="prop='bind was triggerd Again!'"/> </mx:Application> 声明可绑定ActionScript类 在公共类定义前,使用[Bindable]声明该类是可绑定的。 声明ActionScript类可绑定意味着告诉Flex,这个类的所有公共属性都是可绑定的。因此,代码13-4、代码13-5具有相同的意义。 代码13-4:可绑定ActionScript类一 package com.longfei.bookLabs.bookStore.model {     [Bindable]     public class Employee     {         public var name:String;         public var title:String;         public function Employee(){         }     } } 代码13-5:可绑定ActionScript类二 package com.longfei.bookLabs.bookStore.model {     public class Employee     {         [Bindable]         public var name:String;         [Bindable]         public var title:String;         public function Employee(){         }     } } 声明可绑定方法 在Flex中,方法也可以作为数据绑定的数据源,前提条件是方法的参数必须声明为可绑定的属性变量。当属性变量发生变化时,方法就会被调用,并把结果传递给目标数据,如代码13-6所示。 代码13-6:可绑定ActionScript方法 <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"   verticalAlign="middle"  backgroundColor="white">     <mx:Script>         <![CDATA[             private var strDest:String;             private function functionSrc(value:Object):String{                 strDest="新数据是: " + value;                 return strDest;             }         ]]>     </mx:Script>         <mx:Form>             <mx:FormItem label="数据源:">                 <mx:TextInput id="txtSrc" />             </mx:FormItem>             <mx:FormItem label="目标数据:">                 <mx:TextInput id="txtDest" text="{functionSrc(txtSrc.text)}"/>             </mx:FormItem>         </mx:Form>    </mx:Application> 13.2.2  MXML定义数据绑定 使用MXML,可以通过{}句法或<mx:Binding>标签完成数据绑定(如图13-2所示)。下面两段代码13-7、13-8实现了相同的结果。 代码13-7:使用{}句法进行数据绑定 <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"   verticalAlign="middle"  backgroundColor="white">       <mx:Form>             <mx:FormItem label="数据源1:">                 <mx:TextInput id="txtSrc1" />             </mx:FormItem>             <mx:FormItem label="数据源2:">                 <mx:TextInput id="txtSrc2" />             </mx:FormItem>                        <mx:FormItem label="目标数据:">                 <mx:TextInput id="txtDest" text="{'信息来自:' + txtSrc1.text + ' 和               '+ txtSrc2.text}"/>             </mx:FormItem>         </mx:Form>    </mx:Application> 代码13-8:使用<mx:Binding>句法进行数据绑定 <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"   verticalAlign="middle"  backgroundColor="white">       <mx:Form>             <mx:FormItem label="数据源1:">                 <mx:TextInput id="txtSrc1" />             </mx:FormItem>             <mx:FormItem label="数据源2:">                 <mx:TextInput id="txtSrc2" />             </mx:FormItem>                        <mx:FormItem label="目标数据:">                 <mx:TextInput id="txtDest"/>             </mx:FormItem>         </mx:Form>            <mx:Binding source="'信息来自:' + txtSrc1.text + '和' +  txtSrc2.text"         destination="txtDest.text"/>        </mx:Application> 图13-2  在MXML中进行数据绑定 在上面两个代码示例中,绑定的数据源都是txtSrc1.text和txtSrc2.text,而绑定目标是txtDest.text。Flex对数据绑定要做的事情就是,当绑定的数据源发生变化时,将新的数据复制到绑定目标上。 使用{}句法,{}内包含的属性就是绑定的数据源,其中也可以包含ActionScript代码结合绑定数据源构成完整的表达式。 使用<mx:Binding>时,source属性是绑定的数据源,而destination则是绑定目标。在<mx:Binding>标签中,也可以在source属性中包含{}。在我们上面的样例代码中没有包含{},那么source属性中的值被视为单一的ActionScript代码表达式,这就像source属性的值被完全包含在{}中一样。 例如,代码13-8中<mx:Binding>标签代码可以改写成如下格式。{}中的代码被视为ActionScript表达式。 <mx:Binding source="{'信息来自:' + txtSrc1.text + '和' +  txtSrc2.text }" destination="txtDest.text"/> 这段代码也可以改为如下方式: <mx:Binding source="信息来自:{ txtSrc1.text }和{ txtSrc2.text }}" destination="txtDest.text"/> 在这里,source属性的值被视为串联在一起的代码表达式。 13.2.3  ActionScript定义数据绑定 在ActionScript中,使用mx.binding.utils.BindingUtil类完成数据绑定。BindingUtil提供了两个静态方法分别完成绑定属性(bindProperty方法)和绑定方法(bindSetter方法)。 bindProperty() bindProperty()方法签名 public static function bindProperty(site:Object, prop:String, host:Object, chain:Object, commitOnly:Boolean= false):ChangeWatcher bindProperty把对象host的属性或属性链的值(由chain参数说明)绑定到对象site的公共属性prop上。更准确地说,Flex将监控host对象中由chain参数声明的公共属性或属性链,当这些属性发生变化时,将会复制新值到site对象的prop属性上。 bindSetter()方法 bindSetter()方法签名 public static function bindSetter(setter:Function, host:Object, chain:Object, commitOnly:Boolean= false):ChangeWatcher bindSetter()与bindProperty()方法类似,不同的是把对象host的属性或属性链的值(由chain参数说明)传递给setter方法,由setter方法返回最终结果。setter()方法事实上就与绑定相关的事件侦听器方法。bindSetter()方法提供了更多的空间,开发者能够在绑定发生时进一步的处理数据,而不仅仅是单纯的绑定属性。 ChangeWatcher类 bindProperty()方法和bindSetter()都返回ChangeWatcher类实例。类如其名,mx.binding.utils.ChangeWatcher类负责监控绑定数据源的属性或属性链,当它们发生变化时获取通知,调用事件侦听器。关于ChangeWatcher类的具体说明请参考“ActionScript 3.0语言参考”。 在代码13-9中,应用初始化时调用initBinding()方法绑定了txtSrc.text(源)和txtDest.text(目标),也获取了该绑定的ChangeWaatcher实例cw。cw.setHandler方法修改了绑定事件发生后的侦听器方法,也就是说我们用自己的watcherListner()方法替换了bindProperty()默认的事件处理方法。 watcherListner()从cw.getValue()获取所监控属性或属性链的更新数据,并复制到目标对象(txtDest.text)上。一切都与绑定的默认行为一样。只不过我们埋下了一个圣诞彩蛋,如果txtSrc.text的值为“unbind”的时候,就利用cw.unwatch()解除绑定。 代码13-9:ChangeWatcher类的样例 <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"  verticalAlign="middle" backgroundColor="white" creationComplete="initBinding()">     <mx:Script>         <![CDATA[             import mx.controls.Alert;             import mx.binding.utils.*;             private var cw:ChangeWatcher;             private function initBinding():void{                 cw=BindingUtils.bindProperty(txtDest,"text",txtSrc,"text");                 cw.setHandler(watcherListner);             }             private function watcherListner(event:Event):void{                 if(txtSrc.text=="unbind"){                     txtDest.text=cw.getValue().toString();                     cw.unwatch();                 }else{                     txtDest.text=cw.getValue().toString();                 }             }         ]]>     </mx:Script>     <mx:Form>         <mx:FormItem label="数据源">             <mx:TextInput id="txtSrc"/>         </mx:FormItem>         <mx:FormItem label="绑定目标">             <mx:TextInput id="txtDest"/>         </mx:FormItem>     </mx:Form> </mx:Application> 该样例的运行结果如图13-3所示,在“数据源”中输入unbind后,绑定关系就被解除了。 图13-3  ChangWatcher类使用示例 属性链 数据绑定中很重要的一环就是指定监听哪些数据源。Flex不仅可以监控单一的属性,也能够监控属性链。 在下面这个例子中,属性链为book.name,属性链中的任何一环发生变化,都会调度绑定的事件侦听器方法。 BindingUtils.bindProperty(txtDest,"text",,this,["book","name"]); 使用MXML也能够达到同样的目的: <mx:Text id="txtDest" text="{book.name }"/> 13.3  数据绑定样例――图书信息维护 我们通过一个例子,更好地说明如何在应用中使用ActionScript数据绑定。示例完成后的结果如图13-4所示,代码如代码13-10、代码13-11所示。 图13-4  更新图书信息样例 用户输入书名、价格和ISBN号,输入的内容会同时显示在其下方的描述文本上。点击“创建新书”按钮后,会在数据列表中添加图书的信息。 代码13-10:样例中使用的数据模型――Book.as package com.longfei.bookLabs.bookStore.model {     [Bindable]     public class Book     {         public var name:String;         public var ISBN:String;         public var price:Number;         public function Book(){         }     } } 代码13-11:更新图书信息的样例――主应用bindPOC.mxml <?xml version="1.0" encoding="utf-8"?> <!-- http://blog.flexexamples.com/2007/10/01/data-binding-in-flex/ --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"  layout="vertical" verticalAlign="middle" backgroundColor="white" creationComplete="init();">     <mx:Script>         <![CDATA[             import mx.binding.utils.ChangeWatcher;             import mx.collections.ArrayCollection;             import mx.binding.utils.BindingUtils;             import com.longfei.bookLabs.bookStore.model.Book;                                      //Book数据模型的实例             [Bindable]             public var book:Book=new Book();               //存储新增的所有图书,作为数据表books的数据源             [Bindable]             public var acBooks:ArrayCollection=new ArrayCollection();                         private var cwName:ChangeWatcher;             private var cwISBN:ChangeWatcher;             private var cwPrice:ChangeWatcher;                         //初始化绑定             private function init():void {                 cwName =BindingUtils.bindProperty(book, "name", txtName, "text");                 cwISBN=BindingUtils.bindProperty(book, "ISBN", txtISBN, "text");                 cwPrice=BindingUtils.bindProperty(book, "price", txtPrice, "text");                 BindingUtils.bindProperty(txtBPDesc,"text",book,"name");                 BindingUtils.bindSetter(updateBook,this,["book","name"]);             }                         //绑定方法             private function updateBook(value:String):void{                 txtBSDesc.text="新书的名字是" + value + ",价格为" + book.price;             }                         //新建图书,更新books数据表,创建新的图书实例             private function newBook():void{                 acBooks.addItem(book);                 cwName.unwatch();                 cwISBN.unwatch();                 cwPrice.unwatch();                 book=new Book();                 cwName=BindingUtils.bindProperty(book, "name", txtName, "text");                 cwISBN=BindingUtils.bindProperty(book, "ISBN", txtISBN, "text");                 cwPrice=BindingUtils.bindProperty(book, "price", txtPrice, "text");             }         ]]>     </mx:Script>     <mx:Form>         <mx:FormItem label="书名:">             <mx:TextInput id="txtName" />         </mx:FormItem>         <mx:FormItem label="价格:">             <mx:TextInput id="txtPrice"/>         </mx:FormItem>                  <mx:FormItem label="ISBN:">             <mx:TextInput id="txtISBN"/>         </mx:FormItem>     </mx:Form>     <mx:Text id="txtBPDesc"/>     <mx:Text id="txtBSDesc"/>     <mx:Button id="button1" label="创建新书" click="newBook()"/>     <mx:DataGrid id="books" dataProvider="{acBooks}"/> </mx:Application> 应用的关键点说明,其中涉及的[Bindable]元数据标签和数据集合ArrayCollection,将在本章后面详细介绍。 图13-5  更新图书示例说明 1.     使用[Bindable]元数据标签,声明ActionScript类Book为可绑定类,这意味着其所有公共属性都为可绑定属性,可以作为数据绑定的数据源。 2.     使用[Bindable]元数据标签,在主应用bindPOC.mxml中,声明了变量book和acBooks为可绑定变量。 3.     init()方法分别使用bindProperty()方法绑定数据输入框txtName、txtISBN、txtPrice的text属性到book实例的对应属性上。当用户在输入框输入数据时,就会实时地更新book实例。 4.     init()方法使用bindProperty()和bindSetter()方法分别为txtBPDesc和txtBSDesc进行了数据绑定。txtBSDesc的数据绑定是通过updateBook()方法实现的。 BindingUtils.bindProperty(txtBPDesc,"text",book,"name"); BindingUtils.bindSetter(updateBook,this,["book","name"]); 需要进一步说明的是,它们为txtBPDesc文本控件仅仅绑定了name属性(如上第一行代码),而调用updateBook为txtBSDesc文本控件所做的绑定则监控了属性链:book实例和name属性。这意味着,当book实例发生变化时(用户点击“创建新书”按钮后,就会创建新的book实例),txtBPDesc会失去对新的实例的监控,其显示不会进行更新。而txtBSDesc则仍然会监控新的book实例,并相应得更新数据。在本例的图13-4中,也可以看到txtBPDesc文本控件并没有显示新的书名。 5.     数据表格控件books的dataProvider属性与acBooks数据集合绑定。 6.     用户点击“创建新书”按钮后,book实例被加入到数据集合acBooks中,其结果自动地更新到DataGrid控件books上。在创建新的book实例前(book=new Book()),须要解除当前book实例与文本输入框的绑定,之后为新的book实例重新设定绑定关系。读者可以尝试注释newBook()方法中的unWatch代码行及bindProperty代码,重新运行应用,点击“创建新书”按钮后,在文本框中输入书名等信息,此时会发现文本输入框绑定的仍然是原有的book实例(该实例已被存入acBooks,显示为数据列表的第一行),同步更新的是数据列表的第一行。而当再次点击按钮,添加第二本新书时,新的book实例并没有获取文本框输入的信息,由此添加进来的是空的book实例。图13-6显示了修改代码后,应用运行的结果。 图13-6  错误的代码运行结果 13.4  关键的数据集合类 Flex应用处理数据离不开数据集合类。Flex赋予了数据集合类非凡的能力和重大的责任。许多Flex组件都是数据驱动的组件,例如DataGrid、ButtonBar、ComboBox,无一例外的依赖数据集合类提供数据。常用的数据集合类包括ArrayCollection类和XMLListCollection类。本节将介绍数据集合类的共同特点,以及如何使用ArrayCollection类。 13.4.1  数据集合类介绍 数据集合类通常用作Flex数据驱动组件和原始数据对象之间的数据处理层,通过实现IList和ICollectionView接口提供了访问和操纵数据的统一方法。数据集合类依赖数组和XMLList对象提供原始数据,但在对其包装之后,其具有了更丰富的数据处理能力。 ArrayCollection和XMLListCollection类都继承自mx.collections.ListCollection- View。ListCollectionView实现了IList和ICollectionView接口。从IList和ICollectionView接口,我们能够看到数据集合类支持哪些特别的数据处理能力。 mx.collection.IList接口 与ICollectionView接口相比,IList相对简单。IList接口代表了按顺序组织的项目的集合,实现该接口的类提供了对集合项目元素基于索引的访问和处理方法。 IList接口的方法很好地展现了实现该接口类的能力,见表13-1。 表13-1  mx.collection.IList接口的方法(引自ActionScript3.0 Language Reference) 方法签名描述addItem(item:Object):void向列表末尾添加指定项目addItemAt(item:Object, index:int):void在指定的索引处添加项目getItemAt(index:int, prefetch:int= 0):Object获取指定索引处的项目getItemIndex(item:Object):int如果项目位于列表中(此时getItemAt(index) == item),则返回该项目的索引itemUpdated(item:Object, property:Object= null,oldValue:Object= null, newValue:Object= null):void通知视图,某个项目已更新removeAll():void删除列表中的所有项目 续表 方法签名描述removeItemAt(index:int):Object删除指定索引处的项目并返回该项目setItemAt(item:Object, index:int):Object在指定的索引处放置项目toArray():Array返回与 IList 实现的填充顺序相同的Array 实现IList接口的类能够对集合中的项目元素进行添加、删除和获取操作,这些操作会直接作用到原始数据上。IList没有提供数据排序、筛选及游标操作等高级功能。 mx.collection.ICollectionView接口 ICollectionView是数据集合的视图,可以修改该视图以显示根据各种条件排序的数据,或显示在不修改基本数据的情况下经过筛选后的数据。实现ICollectionView接口的类能够对数据集合进行排序和过滤等操作,这些操作不会改变原始数据。 实现ICollectionView接口的类通过属性接口,允许开发者定义过滤方法和排序类操纵数据集合,见表13-2。 表13-2  mx.collection.ICollectionView接口的公共属性(引自ActionScript3.0 Language Reference) 属性描述filterFunction:Function视图用来消除不符合函数条件的项目的函数length:int此视图中的项目数 sort:Sort将应用于 ICollectionView 的排序 实现ICollectionView接口的类也提供了创建游标的方法,游标提供了对数据集合进行查找、搜索和标记书签的功能,还提供修改方法实现插入和删除。这些操作也会作用到原始数据上,并即时反映到由该集合类驱动的Flex可视化组件上,见表13-3。 表13-3  mx.collection.ICollectionView接口的公共方法(引自ActionScript3.0 Language Reference) 方法签名描述contains(item:Object):Boolean返回指示视图是否包含指定对象的信息createCursor():IViewCursor创建使用此视图的新 IViewCursordisableAutoUpdate():void防止视图调度对集合本身和集合中的项目的更改enableAutoUpdate():void启用自动更新 续表 方法签名描述itemUpdated(item:Object, property:Object = null,oldValue:Object = null, newValue:Object = null):void通知视图,某个项目已更新refresh():Boolean将排序和滤镜应用到视图 13.4.2  集合类在数据绑定中的应用 Flex时刻监控集合类数据的变化,它能够及时更新这些集合类数据驱动的组件。当对数组类型数据源进行数据绑定时,要使用集合类对象,而不是Array或XMLList类型对象。当通过IList和ICollectionView接口方法操作集合类对象(例如ListCollectionView 、ArrayCollection或XMLListCollection)时,数据的更新会即时地调度PropertyChanged事件,触发数据绑定,如代码13-12所示。 代码13-12:数组类型数据绑定 <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"  layout="vertical"     verticalAlign="middle" backgroundColor="white">     <mx:Script>         <![CDATA[             import mx.controls.Alert;             import mx.collections.*;                         [Bindable]             private var arrBooks:Array = new Array("ActionScrip基础", "追风筝的            人", "神秘河");             [Bindable]             private var acBooks:ArrayCollection=new ArrayCollection(arrBooks);             private var myCursor:IViewCursor;                         private function updateData():void{                 arrBooks[2]="数字城堡";    //在数组对象上的更新,无法即时触发数据绑定,               更新List组件             }                         private function removeData():void{                 arrList.dataProvider.removeItemAt(0);    //删除了"神秘河"                 acBooks.removeItemAt(0);                //删除了"追风筝的人"             }         ]]>     </mx:Script>     <mx:HBox>         <mx:List id="arrList" dataProvider="{arrBooks}"/>         <mx:List id="acList" dataProvider="{acBooks}"/>            </mx:HBox> <mx:Label text="arrBooks长度={arrList.dataProvider.length}, acBooks长度 ={acBooks.length}"/>        <mx:HBox>         <mx:Button id="button1" label="更新列表" click="updateData()"/>         <mx:Button id="button2" label="删除数据" click="removeData()"/>            </mx:HBox></mx:Application> 在上面例子中,第一个List组件arrList使用了数组arrBooks作为绑定数据源。此时,Flex会自动将arrBooks数组包装为ArrayCollction类。第二个List组件acList使用了ArrayCollection对象acBooks作为绑定数据源,其包装了数组arrBooks。 “更新列表”按钮调用了updateData()方法,该方法直接更新了arrBooks数组的第三个元素。但更新完毕后,List组件并没有发生变化。也就是说数据绑定没有触发。 图13-7显示了点击“更新列表”按钮后的显示。 图13-7  更新列表后的显示 此时,点击“删除数据”,调用removeData()方法。该方法分别调用了arrList.dataProvider和acBooks的removeItemAt(0)方法。arrList.dataProvider代表了封装arrBooks的ArrayCollection类对象。此时,两行代码分别删除了数组当前的第一个元素,并触发了数据绑定。updateData()方法中对数组的更新也同时显示在List组件上,删除数据后的显示如图13-8所示。 图13-8  删除数据后的显示 13.5  理解ArrayCollection类 上一节,我们介绍了集合类提供了丰富的数据操纵能力,本节,我们将通过ArrayCollection类来具体了解如何应用集合类。 13.5.1  创建ArrayCollection类实例 mx.collection.ArrayCollection类是将Array公开为集合的封装类,可使用ICollectionView或IList接口的方法和属性实现访问和处理ArrayCollection实例。对ArrayCollection实例进行操作会修改数据源,例如,如果对ArrayCollection使用removeItemAt()方法,就会删除基础Array中的项目。 ArrayCollection的MXML语法如下: <mx:ArrayCollection id=””   source="null"/> 下面两段代码分别使用MXML标签和ActionScript代码声明并创建了ArrayCollection实例。 使用MXML代码创建ArrayCollection实例。 <mx:ArrayCollection id="arrColl">         <mx:source>             <mx:Array>                 <mx:Object label=" ActionScript基础" data=" A-1" />                 <mx:Object label="追风筝的人" data="B-1" />                 <mx:Object label="神秘河" data="C-1" />             </mx:Array>         </mx:source> </mx:ArrayCollection> 使用ActionScript代码创建ArrayCollection实例。 private var books:Array = new Array({label:"ActionScript基础", data:"A-1"},{label:"追风筝的人", data:"B-1"},{label:"神秘河", data:"C-1"}); private var acBooks1:ArrayCollection=new ArrayCollection(books); Flex应用的数据通常来自外部文件。或者是SWF应用所在服务器的本地资源文件,或者通过HTTP、Web服务等其他方式获取的远端服务器数据。 代码13-13是一个典型的初始化ArrayCollection实例的XML数据源。数据呈现规则的结构,每一个子节点都具有相同的属性,代表了数据集合中的实例。 代码13-13:xml文件样例――book.xml(位于assets目录下) <?xml version="1.0" encoding="utf-8"?> <books>     <book>         <ISBN>9787806239421</ISBN>            <name>大秦帝国</name>         <price>369.00</price>         <author>孙皓晖</author>         <publication>河南文艺出版社</publication>     </book>     ……     <book>         <ISBN>9787115145543</ISBN>            <name>C++ Primer中文版</name>         <price>99.00</price>         <author>Stanley</author>         <publication>人民邮电出版社</publication>     </book> </books> 有很多种方法可以从服务器端获取数据,包括HTTPService、Web服务、远程对象等,我们将在第18章“访问Web和HTTP服务”(见第421页)做具体介绍。下面的例子中,通过简单的HTTP服务(id为service)读取了服务器本地的XML数据文件。数据读取完毕后,会调度result事件,触发handleData事件侦听方法,把读取的数据置入ArrayCollection实例acBooks中(如代码13-14所示)。由于该变量被绑定在数据表grid上,因此即时更新了grid的显示。 代码13-14:从本地xml文件初始化ArrayCollection实例 <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"  layout="vertical"         verticalAlign="middle"         backgroundColor="white" creationComplete="init()">     <mx:Script>         <![CDATA[             import mx.rpc.events.ResultEvent;             import mx.collections.ArrayCollection;                         [Bindable]             private var acBooks:ArrayCollection=new ArrayCollection();                         //初始化数据                        private function init():void{                 service.send();             }                         //从本地XML数据文件中读取数据到acBooks:ArrayCollection中             private function handleData(evt:ResultEvent):void{                 acBooks=evt.result.books.book;             }         ]]>     </mx:Script>     <mx:HTTPService id="service" url="assets/book.xml" result="handleData(event)"/>     <!--绑定acBooks数据源到表格组件-->     <mx:DataGrid id="grid" dataProvider="{acBooks}"/> </mx:Application> 上述代码最终把XML数据文件转换为ArrayCollection实例。在调试模式下运行上述应用,并监控acBooks变量,可以更加清楚地看到XML数据文件如何存储在ArrayCollection实例中,如图13-9所示。 图13-9  Debug模式下监控ArrayCollection实例acBooks XML数据文件的每个节点被作为独立的对象实例(mx.utils.ObjectProxy对象)依次存储在数据集合中。 13.5.2  筛选数据 ArrayCollection类自ListCollectionView继承了filterFunction属性。 filterFunction:Function[] 通过设置filterFunction属性,为ArrayCollection实例指定筛选数据的方法。该方法必须具有如下形式签名: f(item:Object):Boolean 在设置filterFunction属性后,必须调用refresh()方法,将筛选函数应用到数据集合上,更新集合视图。 以上一节应用为基础。我们在数据列表grid上增加滑动条组件,用户通过该组件设置价格范围达到筛选图书的目的,如代码13-15所示。应用完成后结果如图13-10所示: 图13-10  ArrayCollection筛选数据示例 代码13-15:筛选数据示例 <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"  layout="vertical"         verticalAlign="middle"         backgroundColor="white" creationComplete="init()">     <mx:Script>         <![CDATA[             import mx.events.SliderEvent;             import mx.controls.Alert;             import mx.rpc.events.ResultEvent;             import mx.collections.ArrayCollection;                         [Bindable]             private var acBooks:ArrayCollection=new ArrayCollection();                         //初始化数据                        private function init():void{                 service.send();             }                         //从本地XML数据文件中读取数据到acBooks:ArrayCollection中             private function handleData(evt:ResultEvent):void{                 acBooks=evt.result.books.book;                    //设置acBooks的过滤函数                 acBooks.filterFunction=priceFilter;             }                         //acBooks的价格过滤器             private function priceFilter(item:Object):Boolean{                var isMatch:Boolean = false;                if(item.price>=priceSlider.values[0] && item.price<=              priceSlider.values[1]){                    isMatch = true;                }                             return isMatch;            }                                    //价格滑动条变化后触发,应用过滤方法,更新列表             private function dispatchPriceFilter():void             {                     acBooks.refresh();             }                                ]]>     </mx:Script>     <mx:HTTPService id="service" url="assets/book.xml" result="handleData(event)"/>     <!--控制价格筛选--> <mx:HSlider id="priceSlider" minimum="0" maximum="500" tickInterval="5" snapInterval="5"         width="{grid.width}" thumbCount="2" values="[0,500]" labels="[$0,$500]"         liveDragging="true" change="dispatchPriceFilter()"/>                     <!--绑定acBooks数据源到表格组件-->     <mx:DataGrid id="grid" dataProvider="{acBooks}"/> </mx:Application> HSlider组件说明 mx.controls.HSlider类实现了水平滑动条控件。用户可通过在滑块轨道的终点之间移动滑块来选择值。 maximum和minimum属性分别指定了滑块控件允许的最大和最小值。thumCount指定了Slider 控件所允许的滑块数量。在我们的例子中,使用两个滑块来设定价格范围。此时,每个滑块的值在一起构成了数组,通过属性values可以访问和设定该数组值。默认设置values="[0,500]",使得应用初始化时滑块位于轨道的两端。属性liveDragging设置为true,为滑块启动了实时拖动,此时当用户移动滑块时连续调度change事件。可以看到,我们为change事件的侦听器方法定义为dispatchPriceFilter()。 设置ArrayCollection实例acBooks的过滤器属性 在handleData()方法中,acBooks.filterFunction=priceFilter设定了过滤器属性为priceFilter方法。 过滤器方法:priceFilter(item:Object)说明 过滤器方法通过参数item:Object访问ArrayCollection的每个元素。如果价格范围在滑动条设置值范围内,则返回true,该元素会保留在集合视图中。 dispatchPriceFilter()方法说明 每一次滑动滚动条,都会由于触发change事件,而调用dispatchPriceFilter()方法。在该方法中,调用refresh方法以应用过滤。由于acBooks被绑定在grid数据表上,因此过滤结果会即时反应在应用界面上。 13.5.3  数据排序 ArrayCollection自ListCollectionView继承了sort属性。 sort:Sort[] sort属性用于对 ICollectionView视图进行排序。同数据筛选一样,设置排序不会自动刷新视图,因此必须在设置此属性后调用refresh()方法。开发者须要创建mx.collection.Sort类实例赋予ArrayCollection的sort属性。 mx.collection.Sort类 Sort类提供了在现有视图上建立排序所需的排序信息,其实例通常被赋予ICollectionView视图的sort属性(例如ArrayCollection的sort属性),实现对集合数据视图的排序。 Sort类的常用属性包括: fields:Array  //指定要比较的字段的 SortField 对象,数组类型。 以及 compareFunction:Function//用于在排序时比较项目的方法。 mx.collection..SortField SortField提供对现有视图中的字段或属性建立排序所需的排序信息。mx.collection.Sort类中,数组类型的fields属性中的数组项目即为SortField类实例。 我们为上一节ArrayCollection数据筛选的例子加入排序功能。 1.     在主应用上加入新的按钮,用户点击该按钮则触发“SortData()”方法,进行排序。 <mx:Button label="排序" id="buttonSort" click="sortData()"/> 2.     引入mx.collection.Sort和SortField类。 在<mx:Script>标签中,加入 import mx.collections.Sort; import mx.collections.SortField; 3.     实现SortData()方法。 在<mx:Script>标签中,加入新的方法: private function sortData():void{ var sortBooks:Sort = new Sort(); sortBooks.fields=[new SortField("price"),                                new SortField("ISBN")]; acBooks.sort=sortBooks; acBooks.refresh(); } 在上述代码中,首先创建了Sort类实例。然后分别创建了两个SortField实例(对应集合对象元素的price和ISBN属性),并赋予了Sort实例的fileds属性。在将Sort类实例赋予集合对象acBooks的sort属性之后,通过调用refresh方法刷新了视图,并即时更新了数据表。 按下按钮后的数据表显示如图13-11所示。 图13-11  数据集合ArrayCollection的排序结果 13.5.4  使用游标 ArrayCollection有些类似数据表。数据集合中的每一个元素(通常为复杂对象,也可以是String、int等基本类型)就好比数据表中的一条记录。数据库技术中,通过游标可以在数据表的记录中游历。有的时候,在数据集合中也须要实现类似功能。ListCollectionView提供了createCursor()方法,可以创建能够在数据集合中游历的游标。ArrayCollection继承了该方法。 createCursor()方法 createCursor方法签名: public function createCursor():IViewCursor 该方法创建了基于此视图的新 IViewCursor实现。IViewCursor是定义双向枚举集合视图的接口。此游标提供查找、搜索和标记为书签等功能,还提供修改方法用于插入和删除。 IViewCursor接口的方法和属性,见表13-4、表13-5。 表13-4  mx.collection.IViewCursor接口的公共方法(引自ActionScript3.0 Language Reference) 方法签名描述findAny(values:Object):Boolean查找集合中具有指定属性的项目并将光标定位到该项目findFirst(values:Object):Boolean查找集合中具有指定属性的第一个项目,并将光标定位到该项目findLast(values:Object):Boolean查找集合中具有指定属性的最后一个项目,并将光标定位到该项目insert(item:Object):void在光标的当前位置之前插入指定的项目moveNext():Boolean将光标移动到集合中的下一个项目movePrevious():Boolean将光标移动到集合中的上一个项目remove():Object删除当前项目并返回该项目seek(bookmark:CursorBookmark,offset:int= 0, prefetch:int= 0):void将光标移动到与指定书签位置存在一定偏移量的某个位置 表13-5  mx.collection.IViewCursor接口的属性(引自ActionScript3.0 Language Reference) 方法签名描述afterLast:Boolean如果将光标定位于视图中最后一个项目之后,则此属性为 truebeforeFirst:Boolean如果将光标定位于视图中第一个项目之前,此属性为 truebookmark:CursorBookmark可以访问与当前属性返回的项目相对应的书签current:Object可以访问位于此光标引用的源集合中的位置的对象view:ICollectionView对与此光标关联的 ICollectionView 的引用 游标查找的局限性 IViewCursor实现提供了查找方法(findAny、findFirst和findAny)。通过游标查找数据集合中的元素对象非常方便,但由于这些方法依赖于Sort类(使用了其compareFunction属性),由此带来了许多限制: 1.     只能对排序后的视图调用查找方法;如果视图未排序,则会引发 CursorError。 2.     指定的查询值必须配置为名称-值对。这些名称值必须与排序中指定的属性相匹配。这意味着,一方面查询使用的名称-值对必须包含在排序使用的名称值对(Sort类的fields属性制定)范围内;另一方面,查询指定的集合元素属性顺序必须与排序指定的属性顺序相同。例如:如果mySort.fields属性指定的排序属性次序分别为price、bookName和ISBN,那么游标查询指定的名称值对需为{price:value,bookName:value;ISBN:value}。查询指定的数组集合元素对象的属性不一定覆盖所有的排序属性,但必须保证顺序一致。例如{price:value,bookName:value}是可以接受的查询方法参数。但是{price:value, ISBN:value}则会导致游标查询方法抛出CursorError异常。 我们通过为上一个应用加入查找功能,了解如何实际应用游标进行查找,如代码13-16、图13-12所示。 代码13-16:游标查找的样例 <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"  layout="vertical"         verticalAlign="middle"         backgroundColor="white" creationComplete="init()">     <mx:Script>         <![CDATA[             import mx.collections.SortField;             import mx.events.SliderEvent;             import mx.controls.Alert;             import mx.rpc.events.ResultEvent;             import mx.collections.ArrayCollection;             import mx.collections.Sort;             import mx.collections.SortField;             import mx.collections.IViewCursor;                         [Bindable]             private var acBooks:ArrayCollection=new ArrayCollection();                         private var cursor:IViewCursor;                         //初始化数据                        private function init():void{                 service.send();             }                         //从本地XML数据文件中读取数据到acBooks:ArrayCollection中             private function handleData(evt:ResultEvent):void{                 acBooks=evt.result.books.book;                 //创建游标                 cursor = acBooks.createCursor();             }                                //价格滑动条变化后触发,设置acBooks的过滤函数,并更新列表             private function dispatchPriceFilter():void             {                     acBooks.refresh();             }              //查询方法            private function searchItem(event:Event):void{                    //查询之前进行排序                 var sortBooks:Sort = new Sort();                 //排序使用的属性和其顺序,将决定查询时的查询属性及顺序                 sortBooks.fields=[new SortField("price"),new               SortField("bookName"),new SortField("ISBN")];                 acBooks.sort=sortBooks;                 acBooks.refresh();                 //创建查询属性对象                 var searchObj:Object = new Object();                 //查询属性对象必须在排序使用的属性对象范围内,并保持一致顺序                    searchObj = {price:priceKey.text,bookName:nameKey.text};                    //游标查询                 var result:Boolean = cursor.findAny(searchObj);                 if (result) {                     //定位数据表中记录                     grid.selectedItem=cursor.current;                 } else {                     grid.selectedItem = null;                     mx.controls.Alert.show("抱歉,没有找到!");                 }            }                    ]]>     </mx:Script> <mx:HTTPService id="service" url="assets/book.xml" result= "handleData(event)"/>     <!--通过ApplicationControlBar组织工具条-->     <mx:ApplicationControlBar width="{grid.width}">         <mx:Spacer width="100%"/>         <!--图书名称查询输入框-->         <mx:TextInput id="nameKey" toolTip="图书名称" />         <!--图书价格查询输入框-->         <mx:TextInput id="priceKey" toolTip="价格" />         <mx:Button id="buttonSearch" label="查找" click="searchItem(event);" />     </mx:ApplicationControlBar>     <!--绑定acBooks数据源到表格组件-->     <mx:DataGrid id="grid" dataProvider="{acBooks}"/> </mx:Application> 图13-12  ArrayCollection游标查找样例应用  

展开全文

推荐文章

猜你喜欢

附近的人在看

推荐阅读

拓展阅读

《Adobe Flex 大师之路》其他试读目录

• 第2章 Flex全记录
• 第6章 事件驱动编程
• 第13章 数据基础 [当前]
• 第19章 访问远程服务