画面コントロール

Flex2で画面をコントロールする方法です。パターンとして4つ挙げました。

  • A,MXML内ですべて定義(イベントハンドリングはスクリプトで定義)
  • B,MXML内ですべて定義(イベントハンドリングはタグで定義)
  • C,MXML+コントロール用AS(イベントハンドリングはASで定義)
  • D,MXML+コントロール用AS(イベントハンドリングはMXMLで定義)

「ボタンを押すとアラートが出る」というアプリで、例を挙げます。
(動くものはhttp://www.souko105.net/~hatena/20070122/FlexControl.htmlで見れます)

タイプA

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="25" creationComplete="init()">
	<mx:Script>
		<![CDATA[
			import mx.controls.Alert;
			import mx.events.FlexEvent;
			//Canvas初期化後に呼ばれる
			public function init():void{
				testButton.addEventListener(FlexEvent.BUTTON_DOWN,handleTestButtonDown);				
			}
			//ボタンダウン時のハンドラ
			public function handleTestButtonDown(event:Event):void{
				Alert.show("タイプA");
			}			
		]]>
	</mx:Script>
	<mx:Button label="タイプA" id="testButton"/>	
</mx:Canvas>

タイプB

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="25">
	<mx:Script>
		<![CDATA[
			import mx.controls.Alert;
			import mx.events.FlexEvent;
			//ボタンダウン時のハンドラ
			public function handleTestButtonDown(event:Event):void{
				Alert.show("タイプB");
			}			
		]]>
	</mx:Script>
	<mx:Button label="タイプB" id="testButton" mouseDown="{handleTestButtonDown(event)}"/>	
</mx:Canvas>

AとBはいずれもMXML内だけで記述を行います。
Aは、creationCompeteというイベントを使用しています。このイベントは、UIコンポーネント(この場合Canvas
が初期化完了した後に発生します。初期化後、イベントを取得したいUIコンポーネント(この場合Button)に
対して、イベントハンドラをセットしています。
Bは、UIコンポーネントイベントハンドラに呼び出したいメソッドを直接記述する方法です。

Aは、コンポーネントタグに対してイベントハンドラを記述する必要が無いため、タグ部分がすっきりします。
Bは、イベントハンドラをタグに直接書くため、タグが長くなりイベントとスクリプトの結合度が高くなりますが、
その分直感的です。

次はCとDです。CとDはスクリプト部分をASファイルに外出ししたタイプです。
タイプC(MXML

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="25" xmlns:test="test.*">
	<test:TypeCCanvasControl id="ctrl"/>
	<mx:Button label="タイプC" id="testButton"/>	
</mx:Canvas>

タイプC(AS)

package test{
	import mx.core.IMXMLObject;
	import mx.events.FlexEvent;
	import mx.controls.Alert;
	import flash.events.Event;
	
	public class TypeCCanvasControl implements IMXMLObject{
		private var parent:TypeCCanvas;
		public function initialized(document:Object, id:String):void{
			parent = TypeCCanvas(document);
			//MXMLの初期化後のコールバック
			parent.addEventListener(FlexEvent.CREATION_COMPLETE,handleParentCreationCompolete);			
		}
		public function handleParentCreationCompolete(event:FlexEvent):void{
			//画面上のコンポーネントにハンドラをセット
			parent.testButton.addEventListener(FlexEvent.BUTTON_DOWN,this.handleTestButtonDown);	
		}		
		public function handleTestButtonDown(event:Event):void{
			Alert.show("タイプC");
		}
	}
}

タイプD(MXML

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="25" xmlns:test="test.*">
	<test:TypeDCanvasControl id="ctrl"/>
	<mx:Button label="タイプD" id="testButton" mouseDown="{ctrl.handleTestButtonDown(event)}"/>	
</mx:Canvas>

タイプD(AS)

package test{
	import mx.core.IMXMLObject;
	import mx.events.FlexEvent;
	import mx.controls.Alert;
	import flash.events.Event;
	
	public class TypeDCanvasControl implements IMXMLObject{
		private var parent:TypeDCanvas;
		public function initialized(document:Object, id:String):void{
			parent = TypeDCanvas(document);
		}
		public function handleTestButtonDown(event:Event):void{
			Alert.show("タイプD");
		}
	}
}

スクリプトを外だしするために、ASクラスにmx.core.IMXMLObjectというインターフェースをつけています。
このインターフェースは、
「IMXMLObject インターフェイスは、MXML コンパイラを正しく機能させるためにビジュアルではないコンポーネントが 実装する必要のある API を定義します」
http://livedocs.macromedia.com/flex/2_jp/langref/mx/core/IMXMLObject.html
というインターフェースで、initializedというメソッドが定義されています。
ASクラスを作成後、MXML上でタグを書く(この場合、の部分)と、
TypeCCanvasControlがインスタンス化され、TypeCCanvasを引数にしてinitializedメソッドの呼び出しを
してくれます。ASクラスでは、引数で来たオブジェクトを保持することで、MXMLへのアクセスが可能になります。
(parent.コンポーネントIDで、MXML上のオブジェクトにアクセスできます。)
タイプCで、initializedメソッド内でハンドラをつけずにFlexEvent.CREATION_COMPLETEでハンドラをセット
しているのは、initializedメソッドが呼ばれた時点では他のUIコンポーネントが初期化されているかどうか
分からないためです(initializedメソッド内でparent.testButton.addEventListenerを呼び出すと、実行時に
エラーになります)
タイプCとタイプDの違いは、タイプAとタイプBの違いと同じで、ハンドラをASからセットしに行く(タイプC)か、
MXMLにハンドラを直接書く(タイプD)かの違いです。

画面定義とスクリプトが一番疎結合なのがタイプC、一番コードが少ない&わかりやすいのがタイプBかと
思います。