アーカイブ

Repeater で DataGrid もどき

実は、つい最近まで Repeater コンポーネントの存在を知らなかった taiga です。こんにちは。

Repeater コンポーネントの存在を知ってドキュメントを読んだとき、サンプルコードには、<mx:Script> タグを使用していたり、MXML 内で波括弧を使用して AS を埋め込んでいたりと、あまり模範にしたくない断罪サンプルしか掲載されてなかったので、自分好みのサンプルを作成しました。カスタムコンポーネントを Repeater で繰り返し処理させるサンプルです。

RepeaterSample (画面)
http://labs.taiga.jp/flex2/RepeaterSample/

RepeaterSample (ソース)
http://labs.taiga.jp/flex2/RepeaterSample/srcview/

ソースの説明をする前に、Repeater コンポーネントを知らない人向けに簡単に説明しておきます。
Repeater コンポーネントは、実行時に動的 or 静的な配列に基いて UI コンポーネントを繰り返し処理するコンポーネントです。Repeater.dataProvider = hogeArray 的な使い方ができるので、 ComboBox や DataGrid を使ったことのある人であれば、容易に理解できると思います。他にも、for 文で new して addChild() して…といった AS コーディングの手間を省くことができるというメリットもあります。

ソースの説明に話を移しますが、Repeater コンポーネントを持つ親コンポーネント(RepeaterSample.mxml, ApplicationBase.as)では、特別な処理を行っていません。 今回注目したいのは、繰り返し表示されるカスタム子コンポーネントクラス (SubRowBase.as) の中身です。

public function SubRowBase()
{
    addEventListener(FlexEvent.INITIALIZE, initializeHandler, false, 0, true);
}
private function initializeHandler(event:FlexEvent):void
{
    var lColor:uint = (0 == repeaterIndex % 2) ? 0xffffff : 0xeeeeee;
    mComponent = event.currentTarget as SubRow;
    with (mComponent) {
        compCheckBox.addEventListener(Event.CHANGE, changeHandler, false, 0, true);
        compCheckBox.selected = repeater.currentItem.check;
        comp_0_Label.text     = repeater.currentItem.labelFirst;
        comp_1_Label.text     = repeater.currentItem.labelSecond;
        setStyle('backgroundColor', lColor);
        setStyle('backgroundAlpha', 0.5);
    }
}

Repeater コンポーネントにネストされた子コンポーネントは、親コンポーネントから渡された配列の値を、自分自身の repeater.currentItem プロパティを使用して参照することができます。( repeater プロパティは、UIComponent クラスから派生したすべてのコンポーネントに実装されているプロパティです)

このとき注意しなければならないのは、FlexEvent.CREATION_COMPLETE イベント発行のタイミングで repeater プロパティを参照すると、null 参照になり例外エラーが発生するということです。実際に FlexEvent.INITIALIZE イベントを addEventListener している理由は、この例外エラーを回避するためなのです。

次に、子コンポーネント内のデータの変更方法について、CheckBox の Event.CHANGE イベントリスナー関数を例に説明します。

private function changeHandler(event:Event):void
{
    var lRowIndex:int     = repeaterIndex;
    var lSelected:Boolean = event.currentTarget.selected;
    repeater.dataProvider[lRowIndex].check = lSelected;
}

repeaterIndex プロパティは、親コンポーネントの Repeater.dataProvider プロパティ内にある、子コンポーネントのインデックスを取得することができます。( repeaterIndex プロパティも、repeater プロパティと同じく、UIComponent クラスから派生したすべてのコンポーネントに実装されているプロパティです。余談ですが、サンプル画面のストライプの表現でも、repeaterIndex プロパティを使用して、インデックスが偶数か奇数かを判別して背景色を切り替える処理を行っています。)

そして、repeater.dataProvider プロパティを使用することによって、親コンポーネントの Repeater.dataProvider プロパティを参照できるので、子コンポーネントのデータが更新されたときには、repeater.dataProvider[repeaterIndex] に対してデータの変更(上書き)処理を行えばよいわけです。

以上のポイントさえ抑えておけば、Repeater コンポーネントを使用したときでも、MXML コーディングはシンプルかつ最小限に留め、画面のコントロールはすべて AS クラスにまとめる…という、ステキアーキテクチャが割と簡単にできあがるハズです。