Flex の Binding 具体例と内部事情の覗き見
昨日の Flex の Bindable 入門 の続きです。
Binding を MXML で具体的に説明してみます。
データバインディングを使わなかったら
データバインディングを使わない場合を MXML で書いてみました。
<?xml version="1.0"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="init()"> <mx:Script> private function init():void { input1.addEventListener("change", onchange); } private function onchange(e:Event):void { label1.text = "Input text: " + input1.text; } </mx:Script> <mx:TextInput id="input1" /> <mx:Label id="label1" /> </mx:Application>
applicationComplete は JavaScript でいう onload みたいなものです。このなかで init 関数を呼び出して初期化を行います。
init 関数の中は、input1 に対して addEventListener でイベント登録してます。「input1 の中身に変化があったら onchange 関数に通知してね」とお願いしてるわけです。
ハンドラ(onchange 関数)の中では、input1 に入力された文字の前に "Input text: " を加えて、label1 に表示してます。
テキストボックスに入力した内容が、即座に表示される、という簡単な SWF です。
データバインディングを使ってみる
これを Binding を使って書き直してみるとこうなります。
<?xml version="1.0"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="init()"> <mx:Script> private function init():void { } </mx:Script> <mx:TextInput id="input1" /> <mx:Label id="label1" text="Input text: {input1.text}" /> </mx:Application>
Flex の Bindable 入門 では、監視したいデータに [Bindable] をつけましょう、と説明しました。ここでは、input1 の text プロパティを監視したいのですが、実は text プロパティは [Bindable] がついた状態で定義されています。text プロパティは、変更を他に通知する前提で作られている、ということです。
このことはFlex リファレンス ガイドでも確認できます。
次は通知を受け取る側です。受け取る側は中括弧をつけて {mySlider.value} のようにやる、と説明しました。ここでは、input1 の text プロパティを label1 の text プロパティに反映させるわけですから
<mx:Label id="label1" text="Input text: {input1.text}" />
となります。
いかがでしょう。1箇所だけだとあまり効果ははっきりしませんが、複数個所になってくると効果は歴然です。中括弧の中では関数呼び出しや演算などもできるので、自由度はかなり高いです。
技術的に掘り下げてみる
ここからはプログラマ向け。
中括弧で囲んだ場所では、いったいどういうことになってるんでしょうか。
mxmlc のコンパイルオプションに -keep をつけると、MXML がどういう ActionScript に変換されているのかを知ることができます。
MXML のファイル名が test.mxml だとすると generated/test-generated.as に MXML の変換結果が出力されます。
データ変更のイベントを受け取る部分を抜粋してみます。
private function _test_bindingsSetup():void { // 中略 var binding:Binding; binding = new mx.binding.Binding(this, function():String { var result:* = "Input text: " + (input1.text); var stringResult:String = (result == undefined ? null : String(result)); return stringResult; }, function(_sourceFunctionReturnValue:String):void { label1.text = _sourceFunctionReturnValue; }, "label1.text"); _bindings[0] = binding; }
mx.binding.Binding クラスが出てきて複雑ですが、イベントを受け取ったときの処理を Binding クラスを使ってと登録しています。処理内容は第2引数の関数を実行して、その戻り値を第3引数に渡す、という流れです。
ソースをさらに追うと、第4引数は mx/binding/BindingManager.as の中で力技でパースしていたりして面白いのですが、なにせ Flex SDK のソースは分量も多くて複雑なので、なかなか全体像は把握しきれません。興味のある人は SDK の frameworks/source/mx の中にソースがあるので、ぜひ挑戦してみてください。