MXMLでのコンポーネントの継承の方法


MXMLファイルを共通化するために、それ自体を親クラスにすることは少ないと思いますが、今回そのような機会があったので覚え書きです。

パッケージ構成

ソースコード

Indexファイル

まずは、Parent.mxmlを継承した ChildA.mxml/ChildB.mxml/ChildC.mxmlを配置します。

Index.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"
               xmlns:mx="library://ns.adobe.com/flex/mx"
               minWidth="955"
               minHeight="600"
               xmlns:view="main.view.*"
               xmlns:map="main.map.*">

    <fx:Script>
        <![CDATA[
            protected function change_value(event:MouseEvent):void
            {
                childA.model.strValue="イベント発生!!";
            }
        ]]>
    </fx:Script>

    <fx:Declarations>
        <!-- 使用するEventMapを 以下に追記する -->
        <map:ParentEventMap/>

    </fx:Declarations>

    <s:VGroup top="20"
              left="20">
        <!--Child Viewを配置する-->
        <s:HGroup gap="10">
            <view:ChildA click="change_value(event)"
                          id="childA"/>
            <view:ChildB id="childB"/>
            <view:ChildC id="childC"/>
        </s:HGroup>
    </s:VGroup>
</s:Application>

EventMap

イベントマップでモデルクラスをインスタンス化し、各子Viewに親となるParentModelをインジェクトします。

ParentEventMap.mxml
<?xml version="1.0" encoding="utf-8"?>
<mt:EventMap xmlns:fx="http://ns.adobe.com/mxml/2009"
             xmlns:s="library://ns.adobe.com/flex/spark"
             xmlns:mx="library://ns.adobe.com/flex/mx"
             xmlns:mt="http://mate.asfusion.com/">

    <fx:Script>
        <![CDATA[
            import extend.model.ParentModel;
            import extend.view.ChildA;
            import extend.view.ChildB;
            import extend.view.ChildC;
            import extend.view.Parent;

            import mx.events.FlexEvent;
        ]]>
    </fx:Script>

    <fx:Declarations>
        <!-- Modelのインスタンス化 dispatchを引数とする -->
        <mt:EventHandlers type="{FlexEvent.PREINITIALIZE}">
            <mt:ObjectBuilder generator="{ParentModel}"
                              constructorArguments="{scope.dispatcher}"/>
        </mt:EventHandlers>


        <!-- ViewにModelをインジェクトする -->
        <mt:Injectors target="{ChildA}">
            <mt:PropertyInjector source="{ParentModel}"
                                 targetKey="model"/>
        </mt:Injectors>
        <mt:Injectors target="{ChildB}">
            <mt:PropertyInjector source="{ParentModel}"
                                 targetKey="model"/>
        </mt:Injectors>
        <mt:Injectors target="{ChildC}">
            <mt:PropertyInjector source="{ParentModel}"
                                 targetKey="model"/>
        </mt:Injectors>

    </fx:Declarations>
</mt:EventMap>

モデルクラス

ParentModel.as
package extend.model
{
    import flash.events.IEventDispatcher;

    public class ParentModel
    {
        /**
         * コンストラクタ
         */
        public function ParentModel(dispatcher:IEventDispatcher)
        {
            this.dispatcher=dispatcher;
            this.strValue="クリックしてください。"
        }
        protected var dispatcher:IEventDispatcher;

        /**
         * Childで使用する変数
         */
        private var _strValue:String;

        [Bindable]
        public function get strValue():String
        {
            return _strValue;
        }

        public function set strValue(value:String):void
        {
            _strValue=value;
        }
    }
}

親MXMLファイル

親クラスでは、[Bindable]にてModel変数を宣言します。

Parent.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
         xmlns:s="library://ns.adobe.com/flex/spark"
         xmlns:mx="library://ns.adobe.com/flex/mx"
         width="200"
         height="40">

    <fx:Script>
        <![CDATA[
            import extend.model.ParentModel;
            import mx.events.FlexEvent;

            [Bindable]
            public var model:ParentModel;
        ]]>
    </fx:Script>
</s:Group>

子MXMLファイル

ChildA.mxml
<?xml version="1.0" encoding="utf-8"?>
<view:Parent xmlns:fx="http://ns.adobe.com/mxml/2009"
             xmlns:s="library://ns.adobe.com/flex/spark"
             xmlns:mx="library://ns.adobe.com/flex/mx"
             xmlns:view="extend.view.*">

    <s:HGroup>
        <s:Label text="Child A"/>
        <s:TextInput text="{this.model.strValue}"/>
    </s:HGroup>
</view:Parent>
ChildB.mxml
<?xml version="1.0" encoding="utf-8"?>
<view:Parent xmlns:fx="http://ns.adobe.com/mxml/2009"
             xmlns:s="library://ns.adobe.com/flex/spark"
             xmlns:mx="library://ns.adobe.com/flex/mx"
             xmlns:view="extend.view.*">

    <s:HGroup>
        <s:Label text="Child B"/>
        <s:TextInput text="{this.model.strValue}"/>
    </s:HGroup>
</view:Parent>
ChildC.mxml
<?xml version="1.0" encoding="utf-8"?>
<view:Parent xmlns:fx="http://ns.adobe.com/mxml/2009"
             xmlns:s="library://ns.adobe.com/flex/spark"
             xmlns:mx="library://ns.adobe.com/flex/mx"
             xmlns:view="extend.view.*">

    <s:HGroup>
        <s:Label text="Child C"/>
        <s:TextInput text="{this.model.strValue}"/>
    </s:HGroup>
</view:Parent>

実行結果

結果としては、ChildA.mxml/ChildB.mxml/ChildC.mxmlは、同一の親Modelをインジェクトされている為、親Modelで定義している変数値を、同様の結果として表示します。

まあ、滅多に無いケースだと思いますが・・・。
変数の参照の検証として。