Flex 3快速入门(17): 构建高级用户界面 使用数据提供程序
?
<mx:Application??? xmlns:mx="http://www.adobe.com/2006/mxml"
??? viewSourceURL="src/DataProviderArray/index.html"
??? width="150" height="140"
>
??? <mx:Script>
??????? <![CDATA[
??????????? [Bindable]
??????????? public var myArray:Array = ["AL", "AK", "AR"];
??????? ]]>
??? </mx:Script>
??? <mx:ComboBox id="statesCombo" dataProvider="{myArray}"/>
</mx:Application>
限制性数组和对象作为数据提供器
使用原始数据对象,比如数组或对象,有一些局限性:
?
原始数据对象没有提供高级工具,比如访问,保存或过滤数据。比如,如果使用Array作为作为数据提供器,就只能使用Adobe? Flash? Array 的方法操作数据。
注意:这个局限是在Flex2中新产生的。在Flex 1.5或更早的版本中,当数组作为数据提供器的死后,Flex习惯于把事件分发机制与访问、保存和过滤方法混合在一起。这一点在把应用程序从Flex 1.5向2.0或30上迁移时是必须紧记的。在下一节中,我们使用新的Collection类克服这个局限。
在下边的例子中,使用数组作为List控件数据提供器,显示3个博客的名字。当用户按下“Add A Blogger”按钮,Flex增加第四个博客名字到数组中。然而被增加的名字没有马上显示在List控件中,除非你按“Reassign Data Provider”按钮,重新指定这个控件的dateProvider属性。
例子
<?xml version="1.0" encoding="utf-8"?><mx:Application
??? xmlns:mx="http://www.adobe.com/2006/mxml"
??? viewSourceURL="src/DataProviderArrayLimitations/index.html"
??? width="350"??? height="220"
>??? <mx:Script>
??????? <![CDATA[
??????????? [Bindable]
??????????? public var bloggersArray:Array =
??????????????? ["Andy Budd", "Grant Skinner", "Paul Booth"];
??????? ]]>??? </mx:Script>
??? <mx:Panel title="Bloggers we love!" width="100%">
??????? <mx:List
??????????? id="bloggersList" width="100%" rowCount="4"
??????????? dataProvider="{bloggersArray}"??????? />????????
??? </mx:Panel>
??? <mx:ApplicationControlBar>
??????? <mx:Button
??????????? label="Add a blogger!"
??????????? click="bloggersArray[3]='Pete-Barr Watson';"??????? />
??????? <mx:Button
??????????? label="Reassign data provider."
??????????? click="bloggersList.dataProvider=bloggersArray"
??????? />???????????????
??? </mx:ApplicationControlBar></mx:Application>
使用集合作为数据提供器(通过使用MXML)
Flex 提供一个集合机制来确保数据同步,并且提供简单先进的数据访问和操作方式。
你能够使用一个实现了ICollectionView 或者 IList 接口 的对象直接放在MXML控件标签中,作为数据提供器。MXML和ActionScript都能够做到。
下边的例子展示了使用MXML如何创建一个ArrayCollection并把它作为List组件的数据提供器。
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
??? xmlns:mx="http://www.adobe.com/2006/mxml"
??? viewSourceURL="src/DataProviderArrayLimitations/index.html"
??? width="350"??? height="220"
>??? <mx:Panel title="Bloggers we love!" width="100%">
??????? <mx:List id="bloggersList" width="100%" rowCount="4">
??????????? <mx:dataProvider>
??????????????? <mx:ArrayCollection id="bloggers">
??????????????????? <mx:Object label="Andy Budd" url="http://andybudd.com"/>??????????????????? <mx:Object label="Grant Skinner" url="http://gskinner.com"/>
??????????????????? <mx:Object label="Paul Booth" url="http://paulbooth.com"/>??????????????? </mx:ArrayCollection>
??????????? </mx:dataProvider>
??????? </mx:List>?????????????? <mx:ControlBar horizontalAlign="center">
??????????? <mx:Button
??????????????? label="Add a blogger!"
??????????????? click="bloggers.addItem({label:'Pete-Barr Watson', url:'http://petebarrwatson.com/'});"??????????? />
??????? </mx:ControlBar>??? </mx:Panel>
</mx:Application>
使用集合作为数据提供器(通过使用ActionScript)
下边的例子展示了如何通过ActionScript创建一个ArrayCollection并且把它为List组件的数据提供者。
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
??? xmlns:mx="http://www.adobe.com/2006/mxml"
??? viewSourceURL="src/DataProviderArrayLimitations/index.html"??? width="350"??? height="220"
??? creationComplete="creationCompleteHandler(event);"
>
??? <mx:Script>??????? <![CDATA[
??????????? import mx.collections.ArrayCollection;
??????????? import mx.events.FlexEvent;
???????????
??????????? private var bloggersArray:Array =
??????????? [??????????????? {label: "Andy Budd", url:"http://andybudd.com"},
??????????????? {label: "Grant Skinner", url:"http://gskinner.com"},
??????????????? {label: "Paul Booth", url:"http://paulbooth.com"}??????????? ];
???????????
??????????? [Bindable]
??????????? private var bloggersCol:ArrayCollection;
???????????
??????????? private function creationCompleteHandler(event:FlexEvent):void??????????? {
??????????????? bloggersCol = new ArrayCollection (bloggersArray);???
??????????? }
??????? ]]>??? </mx:Script>
??? <mx:Panel title="Bloggers we love!" width="100%">??????? <mx:List
??????????? id="bloggersList" width="100%" rowCount="4"??????????? dataProvider="{bloggersCol}"
??????? />??????? <mx:ControlBar horizontalAlign="center">
??????????? <mx:Button
??????????????? label="Add a blogger!"
??????????????? click="bloggersCol.addItem({label:'Pete-Barr Watson', url:'http://petebarrwatson.com/'});"??????????? />
??????? </mx:ControlBar>??? </mx:Panel>
</mx:Application>
提示:如果你知道一个控件提供器一直代表特定集合类,你可以使用直接使用这个类。比如在前边使用ArrayCollection的例子。然而,如果你的控件必须能够处理不同的数据类型,比如ArrayCollection 或者 XMLListCollection ,你应该绑定数据提供器到一个ICollectionView 类型的属性中。就像下边的代码一样。(译者:说实话我对这段话也没理解。暂时直译过来。)
[Bindable]
private var bloggersCol:ICollectionView;
使用外部加载的数据作为数据提供器
在富因特网应用程序(RIA)中,从外部载入并显示数据是一个普遍的特性。HTTPService控件是从外部载入数据的机制之一。为了把XML数据通过HTTPService控件读入到Flex数据提供器控件中,需要遍历XML节点,保存到ArrayCollection 中,并绑定到控件的dataProvider属性中
提示:确保你发布数据文件到正确的位置。指定给HTTPService 控件的URL是包含Flex应用程序的HTML文件的相对位置,不是Flex应用程序生成的SWF文件的相对位置。
另外,当为HTTPService控件的URL时,应该一直使用正斜线。当离线测试Flex应用程序的时候,反斜线也可以工作。但是挡在服务器上的时候,可能因为被URL编码%5C而导致错误。
使用HTTPService控件的lastResult属性可以绑定到数据提供器的控件上。然而,下边例子展示了稍微更详细的方法使代码更容易维护和扩展。
下边例子使用HTTPService控件读入一个XML文件,并把读入的数据作为List控件的数据提供器。
例子
Model (bloggers.xml)
<bloggers>
??? <blogger>
??????? <name>Andy Budd</name>
??????? <url>http://andybudd.com</url>
??? </blogger>??? <blogger>
??????? <name>Grant Skinner</name>
??????? <url>http://gskinner.com</url>
??? </blogger>
??? <blogger>??????? <name>Paul Booth</name>
??????? <url>http://paulbooth.com</url>
??? </blogger>???
</bloggers>
Main application file
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
??? xmlns:mx="http://www.adobe.com/2006/mxml"
??? viewSourceURL="src/DataProviderExternal/index.html"??? width="350"??? height="220"
??? creationComplete="bs.send();"
>
??? <mx:Script>??????? <![CDATA[
??????????? import mx.managers.CursorManager;
??????????? import mx.rpc.events.InvokeEvent;
??????????? import mx.controls.Alert;
??????????? import mx.rpc.events.FaultEvent;
??????????? import mx.rpc.events.ResultEvent;
??????????? import mx.collections.ArrayCollection;
???????????
??????????? [Bindable]??????????? private var bloggersCol:ArrayCollection;
???????????
??????????? // Gets called when HTTPService is invoked to
??????????? // request the XML.
??????????? private function bsInvokeHandler(event:InvokeEvent):void??????????? {
??????????????? // Display the busy cursor
??????????????? CursorManager.setBusyCursor();
??????????? }
???????????
??????????? // Gets called when the XML is successfully loaded.
??????????? private function bsResultHandler(event:ResultEvent):void??????????? {
??????????????? // Save a reference to the list of bloggers
??????????????? bloggersCol = event.result.bloggers.blogger;
???????????????
??????????????? // Hide the busy cursor
??????????????? CursorManager.removeBusyCursor();
??????????? }???????????
??????????? private function bsFaultHandler(event:FaultEvent):void
??????????? {??????????????? // There was an error in loading the XML
??????????????? Alert.show (event.fault.message);???
???????????????
??????????????? // Hide the busy cursor
??????????????? CursorManager.removeBusyCursor();
??????????? }
??????? ]]>??? </mx:Script>
???
??? <!-- Service to load in XML -->
??? <mx:HTTPService
??????? id="bs"
??????? url="data/bloggers.xml"??????? invoke="bsInvokeHandler(event);"
??????? result="bsResultHandler(event);"
??????? fault="bsFaultHandler(event);"??? />
???
??? <mx:Panel title="Bloggers we love!" width="100%">??????? <mx:List
??????????? id="bloggersList" width="100%" rowCount="4"??????????? dataProvider="{bloggersCol}"
??????????? labelField="name"
??????? />??????? <mx:ControlBar horizontalAlign="center">
??????????? <mx:Button
??????????????? label="Add a blogger!"
??????????????? click="bloggersCol.addItem({name:'Pete-Barr Watson', url:'http://petebarrwatson.com/'});"??????????? />
??????? </mx:ControlBar>??? </mx:Panel>
</mx:Application>
修改数据提供器的数据,并监听这个事件
在Flex中,Collection类实现了IList接口,这个接口提供一些方法(adding,removing,updating)来修改集合中的元素。可以使用IList接口的方法和属性在ArrayCollection类, XMLList类,和标准Flex控件的dataProvider 属性上。可以使用IList的addItem(), removeItem(), 和setItemAt() 方法分别增加,删除和更新元素数据。addItemAt() and removeItemAt() methods, 和the setItemAt()方法提供第二个参数,下标位置,来指定要在集合中影响的位置。IList接口的length属性返回集合中元素的数量。
Flex的集合机制也包括描述数据改变的事件。实现了IList 或者 ICollectionView 接口的类,无论何时数据发生改变,都分发CollectionEvent类事件所有集合时间都包含类型属性值CollectionEvent.COLLECTION_CHANGE。
注意:你也可以使用ICollectionView接口来保存和过滤数据。更多的信息请查看Flex3开发手册的Using ICollectionView interface methods and properties章节
CollectionEvent对象有kind属性标志着集合被改变的方式。通过kind属性与CollectionEventKind的常量的对比,你可以测试集合所发生的改变。主要的常量包括ADD,REMOVE和 UPDATE。
CollectionEvent对象包含一个items属性这个属性是一个对象的数组,这个数组的类型依赖于对象分发的事件的类型。对于ADD和REMOVE时间,这个数组包含added和removed数组。对于UPDATE事件,这个items属性包含PropertyChangeEvent事件对象数组。这些对象的属性显示出改变的类型和属性改变之前和之后的值。例如,PropertyChangeEvent类的kind属性显示出属性被改变的方式;你可以测试改变的类型通过把kind属性与PropertyChangeEventKind的常量UPDATE或DELETE.
下边的例子监听DataGrid的改变事件,来创建一个概览——详细关系。在这个关系中,选择一个DataGrid中的一行后,数据会显示在几个form控件中,然后你就可以编辑数据了。(使用概览——详细关系可以使DataGrid控件具有可编辑功能)。通过IList接口的addItem(), removeItem(), and setItemAt()方法,可以对DataGrid中的数据增加,删除,修改。这个例子也监听ArrayCollection上的collectionChange时间保持对数据增删改的日志记录。
例子
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
??? xmlns:mx="http://www.adobe.com/2006/mxml"
???? viewSourceURL="src/DataProviderModifyingAndEvents/index.html"
??? width="525" height="530">
??? <mx:Script>
??????? <![CDATA[
???????????
??????????? import mx.events.*;
??????????? import mx.collections.*;
???????????
??????????? // Add event information to a log (displayed in the TextArea).??????????? public function collectionEventHandler(event:CollectionEvent):void
??????????? {
??????????????? switch(event.kind)
??????????????? {??????????????????? case CollectionEventKind.ADD:
??????????????????????? addLog("Item "+ event.location + " added");
??????????????????????? break;
??????????????????? case CollectionEventKind.REMOVE:??????????????????????? addLog("Item "+ event.location + " removed");
??????????????????????? break;
??????????????????? case CollectionEventKind.REPLACE:??????????????????????? addLog("Item "+ event.location + " Replaced");
??????????????????????? break;
??????????????????? case CollectionEventKind.UPDATE:??????????????????????? addLog("Item updated");
??????????????????????? break;
??????????????? }
??????????? }
??????????? // Helper function for adding information to the log.
??????????? public function addLog(str:String):void
??????????? {??????????????? log.text += str + "\n";
??????????? }
???????????
??????????? // Add a person to the ArrayCollection.
??????????? public function addPerson():void
??????????? {??????????????? ac.addItem({first:firstInput.text, last:lastInput.text,
??????????????????????? email:emailInput.text});
??????????????? clearInputs();
??????????? }
???????????
??????????? // Remove a person from the ArrayCollection.??????????? public function removePerson():void
??????????? {
??????????????? // Make sure an item is selected.
??????????????? if (dg.selectedIndex >= 0)
??????????????? {??????????????????? ac.removeItemAt(dg.selectedIndex);
??????????????? }
??????????? }
???????????
??????????? // Update an existing person in the ArrayCollection.
??????????? public function updatePerson():void
??????????? {??????????????? // Make sure an item is selected.
??????????????? if (dg.selectedItem !== null)
??????????????? {
??????????????????? ac.setItemAt({first:firstInput.text, last:lastInput.text,
??????????????????????? email:emailInput.text}, dg.selectedIndex);
??????????????? }??????????? }
???????????
??????????? // The change event listener for the DataGrid.
??????????? // Clears the text input controls and updates them with the contents
??????????? // of the selected item.
??????????? public function dgChangeHandler():void
??????????? {??????????????? clearInputs();
??????????????? firstInput.text = dg.selectedItem.first;
??????????????? lastInput.text = dg.selectedItem.last;
??????????????? emailInput.text = dg.selectedItem.email;
??????????? }
???????????
??????????? // Clear the text from the input controls.??????????? public function clearInputs():void
??????????? {
??????????????? firstInput.text = "";
??????????????? lastInput.text = "";
??????????????? emailInput.text = "";
??????????? }???????
??????? ]]>
??? </mx:Script>
???
??? <!-- The ArrayCollection used by the DataGrid and ComboBox. -->
??? <mx:ArrayCollection id="ac"??????????? collectionChange="collectionEventHandler(event)">
??????? <mx:source>
??????????? <mx:Object first="Matt" last="Matthews" email="matt@myco.com"/>??????????? <mx:Object first="Sue" last="Sanderson" email="sue@myco.com"/>
??????????? <mx:Object first="Harry" last="Harrison" email="harry@myco.com"/>??????? </mx:source>
??? </mx:ArrayCollection>??? <mx:Panel title="Master-Detail View" width="100%">
???????
??????? <mx:DataGrid width="100%" id="dg" dataProvider="{ac}"??????????????? change="dgChangeHandler()">
??????????? <mx:columns>
??????????????? <mx:DataGridColumn dataField="first" headerText="First Name"/>??????????????? <mx:DataGridColumn dataField="last" headerText="Last Name"/>
??????????????? <mx:DataGridColumn dataField="email" headerText="Email"/>
??????????? </mx:columns>??????? </mx:DataGrid>
???????
??????? <!-- Form for data to add or change in the ArrayCollection. -->
??????? <mx:Form label="test" width="100%">?????????? <mx:FormItem label="First Name" width="100%">
??????????????? <mx:TextInput id="firstInput" width="100%"/>?????????? </mx:FormItem>
?????????? <mx:FormItem label="Last Name" width="100%">
??????????????? <mx:TextInput id="lastInput" width="100%"/>?????????? </mx:FormItem>
?????????? <mx:FormItem label="Email" width="100%">
??????????????? <mx:TextInput id="emailInput" width="100%"/>?????????? </mx:FormItem>
??????? </mx:Form>
???
??????? <mx:ControlBar horizontalAlign="center">
??????????? <!-- Buttons to initiate operations on the collection. -->??????????? <mx:Button label="Add New" click="addPerson()"/>
??????????? <mx:Button label="Update Selected" click="updatePerson()"/>??????????? <mx:Button label="Remove Selected" click="removePerson()"/>
??????????? <!-- Clear the text input fields. -->??????????? <mx:Button label="Clear" click="clearInputs()"/>
??????? </mx:ControlBar>??? </mx:Panel>
??? <!-- The application displays event information here -->
??? <mx:Panel title="Change log" width="100%" height="125">???????
??????? <mx:TextArea id="log" width="100%" height="100%"/>??? </mx:Panel>??
</mx:Application>
结果
??