Flex Framework Mate の基本的な使い方 その2

前回の続きです。
http://qiita.com/tajihiro/items/61a377c17b99fcff453c

**サンプル**

下記の図のようなサンプルです。
テキストフィールドに入力した言葉を、ラベルに返すサンプルです。

![input.png](https://qiita-image-store.s3.amazonaws.com/0/3184/2567b66d-6b0e-279f-fbd8-4c9f6e31cc0e.png)
　↓
![output.png](https://qiita-image-store.s3.amazonaws.com/0/3184/de2ae250-e0c3-5fe7-0da4-1bef085322a4.png)


**ソースコード解説**

***アプリケーションエントリ***

Index.mxmlは、アプリケーションのエントリとなるmxmlファイルです。
ここでは、Viewコンポーネントである MainView.mxml(View)を配置し、MainView上で発生するイベントをマッピングする MainViewEventMap.mxml (EventMap)を定義します。

```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:Declarations>
		<!-- 使用するEventMapを 以下に追記する -->
		<map:MainViewEventMap/>

	</fx:Declarations>

	<s:Group top="20"
			  left="20">
		<!--MainViewを配置する-->
		<view:MainView/>
	</s:Group>
</s:Application>
```

***イベントマップ***
このファイルは、Index.mxmlファイル内で呼び出されます。

イベントマップファイルの中では、Flexの初期イベントであるPREINITIALIZEイベントを受けて、MainViewModelクラスをインスタンス化します。
その際、モデルのコンストラクタにて scope.dispathcer を注入(DI)してあげます。

イベントハンドラのマッピング定義ですが、EventHandlersタグの、typeで指定したイベントを受け取ると、MethodInvokerのgeneratorで指定したモデルクラスのメソッドを呼び出します。

Injectorsにてターゲットに Viewコンポーネントを指定し、使用するモデルを定義します。ここで指定する targetKeyで指定した識別子が、Viewが使用するモデルの変数名となります。

```MainViewEventMap.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 main.event.MainViewEvent;
			import main.model.MainViewModel;
			import main.view.MainView;

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

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

		<!-- Eventに対応するModel内のメソッドを定義する パラメータは event より取得-->
		<mt:EventHandlers type="{MainViewEvent.EXEC_FUNC_1}">
			<mt:MethodInvoker generator="{MainViewModel}"
							  method="func1"
							  arguments="{event.inputData}"/>
		</mt:EventHandlers>

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

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

***Viewコンポーネント***
Viewコンポーネントファイルでは、ボタン等のコンポーネントを配置します。
また、[Bindable]なモデルクラスを定義します。

Viewで発生したイベントは、そのイベントハンドラの中で、そのModelファイルへ処理を受け渡します。
この例では、ボタンのクリックイベントに対応した myButton_clickHandler(event)の中で、そのModelクラスのclickHandlerメソッドを、TextInputに入力した文字列を引数にして呼び出しています。

```Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:VGroup 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="400"
		  height="300">

	<fx:Script>
		<![CDATA[
			import main.model.MainViewModel;

			[Bindable]
			public var model:MainViewModel;

			//クリックハンドラ
			protected function myButton_clickHandler(event:MouseEvent):void
			{
				//モデルのクリックハンドラメソッドを呼ぶ
				this.model.clickHandler(this.myText.text);
			}
		]]>
	</fx:Script>

	<fx:Declarations>
		<!-- 非ビジュアルエレメント (サービス、値オブジェクトなど) をここに配置 -->
	</fx:Declarations>

	<s:HGroup>
		<s:TextInput id="myText"
					 text="こんにちは。"/>
		<s:Button id="myButton"
				  label="OK"
				  click="myButton_clickHandler(event)"/>
	</s:HGroup>

	<s:Spacer height="30"/>

	<s:HGroup>
		<s:Label text="戻り値："/>
		<s:Label id="result"
				 text="{this.model.result}"/>
	</s:HGroup>
</s:VGroup>
```


***モデルクラス***

モデルクラスは、Viewでのイベントハンドラ処理等のロジックを記述します。
または、イベントディスパッチされたイベントの後処理を記述します。

```MainViewModel.as
package main.model
{
	import com.asfusion.mate.events.Dispatcher;

	import flash.events.IEventDispatcher;
	import flash.events.MouseEvent;

	import main.event.MainViewEvent;
	import main.view.MainView;

	import mx.controls.Alert;

	public class MainViewModel
	{
		/**
		 * コンストラクタ
		 */
		public function MainViewModel(dispatcher:IEventDispatcher)
		{
			this.dispatcher=dispatcher;
		}

		//親クラスで定義した方が便利
		protected var dispatcher:IEventDispatcher;

		/**
		 * プロパティ
		 */
		private var _result:String;

		/**
		 * プロパティ Getter/Setter
		 */
		[Bindable]
		public function get result():String
		{
			return _result;
		}

		/**
		 * @private
		 */
		public function set result(value:String):void
		{
			_result=value;
		}

		/**
		 * クリックハンドラ(Viewから呼ばれる)
		 */
		public function clickHandler(value:String):void
		{
			var event:MainViewEvent=new MainViewEvent(MainViewEvent.EXEC_FUNC_1);
			//Eventにパラメータを設定
			event.inputData=value;
			this.dispatcher.dispatchEvent(event)
		}

		/**
		 * イベントディスパッチされたハンドラ(EventMapから呼ばれる)
		 */
		public function func1(param:Object):void
		{
			var str:String=param as String;
			result=str;
//			Alert.show("func1:" + str);
		}
	}
}
```

***Eventクラス***

Eventクラスは、 flash.events.Eventクラスを継承しており、イベントの定義を行います。
イベントクラス内では、発生したイベントにパラメータを含めたい場合には、インスタンス変数を定義します。

```MainViewEvent.as
package main.event
{
	import flash.events.Event;

	public class MainViewEvent extends Event
	{
		public static const NAME:String="MainViewEvent";

		//イベント名
		public static const EXEC_FUNC_1:String="execFunc1" + NAME;

		//パラメータデータ
		public var inputData:String;

		public function MainViewEvent(type:String, 
						bubbles:Boolean=false,
						cancelable:Boolean=false)
		{
			super(type, bubbles, cancelable);
		}
	}
}
```

以上、FlexのフレームワークであるMateの基本的な解説でした。
最初は複雑なので戸惑います。
ソースコードや、イベントディスパッチを追うのがとても面倒なのですが、大規模開発の見通しは良いと思います。