| Flex 2 開発ガイド > Flex アプリケーションのユーザーインターフェイスの作成 > データプロバイダおよびコレクションの使用 > 階層データプロバイダの使用 > データ記述子と階層データプロバイダ構造 > カスタムデータ記述子の作成 | |||
階層データが DefaultDataDescriptor クラスでサポートされる形式に適合しない場合、たとえばデータが子フィールドを使用しないオブジェクト内にある場合、カスタムデータ記述子を記述し、Tree コントロールの dataDescriptor プロパティにカスタムデータ記述子を指定できます。カスタムデータ記述子は、ITreeDataDescriptor インターフェイスのすべてのメソッドを実装する必要があります。
次の例は、カスタムデータ記述子の作成方法を示します。ここでは Tree コントロールを使用しています。このデータ記述子は、ネストされた ArrayCollection オブジェクトから成るデータプロバイダを適切に処理します。
次の例の MyCustomTreeDataDescriptor クラスは ITreeDataDescriptor インターフェイスのみを実装しているため、Tree コントロールはサポートしますが、メニューコントロールはサポートしません。このカスタムクラスは、子フィールドが ArrayCollection または Object であるツリーノードをサポートします。ノードの子を取得するとき、子オブジェクトが ArrayCollection の場合には、その子オブジェクトを返します。それ以外の場合は、子オブジェクトを ArrayCollection でラップしてから返します。ノードを追加するときは、子フィールドのタイプによって異なるメソッドを使用します。
package myComponents
// myComponents/MyCustomTreeDataDescriptor.as
{
import mx.collections.ArrayCollection;
import mx.collections.CursorBookmark;
import mx.collections.ICollectionView;
import mx.collections.IViewCursor;
import mx.events.CollectionEvent;
import mx.events.CollectionEventKind;
import mx.controls.treeClasses.*;
public class MyCustomTreeDataDescriptor implements ITreeDataDescriptor
{
// The getChildren method requires the node to be an Object
// with a children field.
// If the field contains an ArrayCollection, it returns the field
// Otherwise, it wraps the field in an ArrayCollection.
public function getChildren(node:Object,
model:Object=null):ICollectionView
{
try
{
if (node is Object) {
if(node.children is ArrayCollection){
return node.children;
}else{
return new ArrayCollection(node.children);
}
}
}
catch (e:Error) {
trace("[Descriptor] exception checking for getChildren");
}
return null;
}
// The isBranch method simply returns true if the node is an
// Object with a children field.
// It does not support empty branches, but does support null children
// fields.
public function isBranch(node:Object, model:Object=null):Boolean {
try {
if (node is Object) {
if (node.children != null) {
return true;
}
}
}
catch (e:Error) {
trace("[Descriptor] exception checking for isBranch");
}
return false;
}
// The hasChildren method Returns true if the node actually has children.
public function hasChildren(node:Object, model:Object=null):Boolean {
if (node == null)
return false;
var children:ICollectionView = getChildren(node, model);
try {
if (children.length > 0)
return true;
}
catch (e:Error) {
}
return false;
}
// The getData method simply returns the node as an Object.
public function getData(node:Object, model:Object=null):Object {
try {
return node;
}
catch (e:Error) {
}
return null;
}
// The addChildAt method does the following:
// If the parent parameter is null or undefined, inserts
// the child parameter as the first child of the model parameter.
// If the parent parameter is an Object and has a children field,
// adds the child parameter to it at the index parameter location.
// It does not add a child to a terminal node if it does not have
// a children field.
public function addChildAt(parent:Object, child:Object, index:int,
model:Object=null):Boolean {
var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
event.kind = CollectionEventKind.ADD;
event.items = [child];
event.location = index;
if (!parent) {
var iterator:IViewCursor = model.createCursor();
iterator.seek(CursorBookmark.FIRST, index);
iterator.insert(child);
}
else if (parent is Object) {
if (parent.children != null) {
if(parent.children is ArrayCollection) {
parent.children.addItemAt(child, index);
if (model){
model.dispatchEvent(event);
model.itemUpdated(parent);
}
return true;
}
else {
parent.children.splice(index, 0, child);
if (model)
model.dispatchEvent(event);
return true;
}
}
}
return false;
}
// The removeChildAt method does the following:
// If the parent parameter is null or undefined, removes
// the child at the specified index in the model.
// If the parent parameter is an Object and has a children field,
// removes the child at the index parameter location in the parent.
public function removeChildAt(parent:Object, child:Object, index:int, model:Object=null):Boolean
{
var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
event.kind = CollectionEventKind.REMOVE;
event.items = [child];
event.location = index;
//handle top level where there is no parent
if (!parent)
{
var iterator:IViewCursor = model.createCursor();
iterator.seek(CursorBookmark.FIRST, index);
iterator.remove();
if (model)
model.dispatchEvent(event);
return true;
}
else if (parent is Object)
{
if (parent.children != undefined)
{
parent.children.splice(index, 1);
if (model)
model.dispatchEvent(event);
return true;
}
}
return false;
}
}
}
次の例では、MyCustomTreeDataDescriptor を使用して、階層的なネストされた ArrayCollection とオブジェクトを処理します。ボタンがクリックされると、データ記述子の addChildAt() メソッドを呼び出してツリーにノードを追加します。通常は addChildAt() メソッドを直接使用することはありません。その代わりに、Tree またはメニューコントロールのメソッドを呼び出します。これらのメソッドは内部でデータ記述子メソッドを使用して、データプロバイダを変更します。
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- dpcontrols\CustDataDescriptor.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" creationComplete="initCollections()">
<mx:Script>
<![CDATA[
import mx.collections.*;
import mx.controls.treeClasses.*;
import myComponents.*;
//Variables used to construct the ArrayCollection data provider
//First top-level node and its children.
public var nestArray1:Array = [
{label:"item1", children: [
{label:"item1 child", children: [
{label:"item 1 child child", data:"child data"}
]}
]}
];
//Second top-level node and its children.
public var nestArray2:Array = [
{label:"item2", children: [
{label:"item2 child", children: [
{label:"item 2 child child", data:"child data"}
]}
]}
];
//Second top-level node and its children.
public var nestArray3:Array = [
{label:"item3", children: [
{label:"item3 child", children: [
{label:"item 3 child child", data:"child data"}
]}
]}
];
//Variable for the tree array.
public var treeArray:Array
//Variables for the three Array collections that correspond to the
//top-level nodes.
public var col1:ArrayCollection;
public var col2:ArrayCollection;
public var col3:ArrayCollection;
//Variable for the ArrayCollection used as the Tree data provider.
[Bindable]
public var ac:ArrayCollection;
//build the ac ArrayCollection from its parts.
public function initCollections():void{
// Wrap each top-level node in an ArrayCollection.
col1 = new ArrayCollection(nestArray1);
col2 = new ArrayCollection(nestArray2);
col3 = new ArrayCollection(nestArray3);
// Put the three top-level node ArrayCollections in the treeArray.
treeArray = [
{label:"first thing", children: col1},
{label:"second thing", children: col2},
{label:"third thing", children: col3},
];
//Wrap the treeArray in an ArrayCollection.
ac = new ArrayCollection(treeArray);
}
// Adds a child node as the first child of the selected node,
// if any. The default selectedItem is null, which causes the
// data descriptor addChild method to add it as the first child
// of the ac ArrayCollection.
public function clickAddChildren():void {
var newChild:Object = new Object();
newChild.label = "New Child";
newChild.children = new ArrayCollection();
tree.dataDescriptor.addChildAt(tree.selectedItem, newChild, 0, ac);
}
]]>
</mx:Script>
<mx:Tree width="200" id="tree" dataProvider="{ac}"
dataDescriptor="{new MyCustomTreeDataDescriptor()}"/>
<mx:Button label="add children" click="clickAddChildren()"/>
</mx:Application>
Flex 2.01