kagamihogeの日記

kagamihogeの日記です。

Flex のデータバインディングのキホン的な使い方

データバインディング - Flex 2

このリファレンス見れば済む話なんですが。基本的に 3 通りあったりしてややこしいんですよね……

中括弧({})を使用するやり方

たぶん一番手軽かつ使用頻度が高い方法。ちょっとしたサンプル書いたり実験したりする場合もコレ使って済ませることが多い。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:Script>
        <![CDATA[
            [Bindable]
            private var sourceText:String="hoge";
            
            private function changed():void {
                sourceText = sourceInput.text;
            }
        ]]>
    </mx:Script>

    <mx:TextInput id="destinationInput" text="{sourceText}" />
    <mx:TextInput id="sourceInput" change="changed()" />
</mx:Application>

バインディングのソース(この例だと sourceText)に指定したプロパティを変更すると、バインディングの宛先(この例だと destinationInput.text)も連動して変更される。

上の例の場合、こう書いても同じ動作になる。

<mx:TextInput id="destinationInput" text="{sourceInput.text}" />
<mx:TextInput id="sourceInput" />

あるテキストに入力された文字を、別のとこに連動させて表示したい、みたいな単純なケースの場合はコレで済む。現実的には、イベントハンドラでなにかしら処理したあと表示、ってことが多いと思うんで、こう書くことはアンマリ無い気がしないでもない。

mx:Binding を使用するやり方

mx:Binding のタグを使うやり方。アンマリ使ったことがない。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:Binding source="sourceInput.text" destination="destinationInput.text"/>

    <mx:TextInput id="destinationInput" />
    <mx:TextInput id="sourceInput" />
</mx:Application>

これも中括弧の例とおんなじで、sourceInput いじると destinationInput も連動する。

中括弧の例との大きな違いは、同じ宛先に異なるソースを指定できる点。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:Binding source="sourceInputA.text" destination="destinationInput.text"/>
    <mx:Binding source="sourceInputB.text" destination="destinationInput.text"/>

    <mx:TextInput id="destinationInput" />
    <mx:TextInput id="sourceInputA" />
    <mx:TextInput id="sourceInputB" />
</mx:Application>

sourceInputA いじると、sourceInputA が destinationInput と連動する。sourceInputB いじると、sourceInputB が destinationInput と連動する。

でもこの書き方はアンマリ使わない気がする。ActionScript のコードでバインディングの設定書きたいケースの方が多いような無いような。

BindingUtils を使用するやり方

AS でデータバインディング設定したい場合はコレを使う。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="init()">
    <mx:Script>
        <![CDATA[
            import mx.binding.utils.BindingUtils;
            
            [Bindable]
            public var sourceText:String="hoge";
            
            private function init():void {
                BindingUtils.bindProperty(destinationInput, "text", this, "sourceText");
            }
            
            private function changed():void {
                sourceText = sourceInput.text;
            }
        ]]>
    </mx:Script>

    <mx:TextInput id="destinationInput" />
    <mx:TextInput id="sourceInput" change="changed()" />
</mx:Application>

この例も sourceInput いじると、destinationInput が変更される。

BindingUtils.bindProperty の引数は、宛先のオブジェクト・宛先のオブジェクトのプロパティ名・ソースのオブジェクト・ソースのオブジェクトのプロパティ名、の順番で指定する。そして、たいてい逆に間違えるw source とか destination とか表記するなら、BindingUtils.bindProperty の引数名もそっちに合わせてくれや、と思う。

上の例は、AS のプロパティ -> mxml のコンポーネントのプロパティ、という方向だった。今度は逆に、mxml のコンポーネントのプロパティ -> AS のプロパティ、の方向をやってみる。つっても、BindingUtils.bindProperty で指定してるソースと宛先を入れ替えするだけですが。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="init()">
    <mx:Script>
        <![CDATA[
            import mx.binding.utils.BindingUtils;

            public var destinationText:String="hoge";
            
            private function init():void {
                BindingUtils.bindProperty(this, "destinationText", sourceInput, "text");
            }
            
            private function clicked():void {
                trace(destinationText);
            }
        ]]>
    </mx:Script>

    <mx:TextInput id="sourceInput" />
    <mx:Button click="clicked()" />
</mx:Application>

プロパティ名や id も内容に合わせて変更してる点に注意。コレで、sourceInput に入力した値が destinationText に勝手に入ってくれます。

というわけで、双方向バインディングの場合は、両方向の設定してやることになります。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="init()">
    <mx:Script>
        <![CDATA[
            import mx.binding.utils.BindingUtils;
            
            [Bindable]
            public var sourceText:String="hoge";
            
            private function init():void {
                BindingUtils.bindProperty(destinationInput, "text", this, "sourceText");
                BindingUtils.bindProperty(this, "sourceText", destinationInput, "text");
            }
            
            private function changed():void {
                sourceText = sourceInput.text;
            }
            
            private function clicked():void {
                destinationInput.text = new Date().toString();
                trace(sourceText);
            }
        ]]>
    </mx:Script>

    <mx:TextInput id="destinationInput" />
    <mx:TextInput id="sourceInput" change="changed()" />
    <mx:Button click="clicked()" />
</mx:Application>

なんかちょっと分かり辛いかもですが(変数名もアレだし) sourceText をいじると、destinationInput.text が連動して変更される。destinationInput.text をいじると、sourceText が連動して変更される。mxml の中に AS のコード入れてるとあんまし甘みがわからんような気がしてきた……

他にも、データバインディングの書式や使い方はてんこもりです。データバインディング - Flex 2 に色々書いてある通り。まぁでも、あんまり色々混ぜこぜに書くと混乱しそうだけど……このドキュメントにはどんな時にどんな書式使うべきか的なガイドラインは無いしねぇ……

最後に BindingUtils 使うときのハマりどころ。

  • ソースのオブジェクトのプロパティは public
    • 「ReferenceError: Error #1069: test4 にプロパティ sourceText が見つからず、デフォルト値もありません。」みたいな実行時エラー出ます。BindingUtils にあるとおり、describeType() で public でないプロパティが見えんから、ってのが理由。理屈じゃわかってんだけど、忘れやすい。
  • ソースと宛先どっちがどっちだよ
    • 上でもちょろっと書いたけど。要指差し確認。
  • 宛先プロパティ名の指定が文字列なので、タイプミスしてると気付かない
    • ありがち。