Flex において大変便利な Bindable 機能について、実は良くわかっていなかったので(主に仕組みが)調べてみました。
Bindable 基礎
とにかく判りやすい機能のサンプルコード。custom.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml" change="onChange()">
<mx:Script>
<![CDATA[
[Bindable] public var itemString:String;
private function onChange():void
{
itemString = selectedItem as String;
}
]]>
</mx:Script>
<mx:dataProvider>
<mx:ArrayCollection>
<mx:Array>
<mx:String>A:アセンブラ</mx:String>
<mx:String>B:ベーシック</mx:String>
<mx:String>C:C言語</mx:String>
<mx:String>D:D言語</mx:String>
<mx:String>E:えっ?</mx:String>
</mx:Array>
</mx:ArrayCollection>
</mx:dataProvider>
</mx:ComboBox>
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:my="*">
<mx:Label text="{id1.itemString}"></mx:Label>
<my:custom id="id1" width="100" height="30"/>
</mx:Application>
この例では、コンボボックスの内容が変化すると、上部のラベルにその変化が反映されます。
custom コントロールの、itemString が [Bindable] です。
子コンポーネントから子コンポーネントへの情報伝達は、Bindable を使えば容易に実現できることが判ります。
親が変化を検出するには
では、親コンポーネントが直接子コンポーネントの変数の変化を知るにはどうしたらよいかと言うと・・・Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:my="*" applicationComplete="init()">
<mx:Script>
<![CDATA[
import mx.events.PropertyChangeEvent;
private function init():void
{
id1.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onChange);
}
private function onChange(e:PropertyChangeEvent):void
{
lb.text = e.newValue as String;
}
]]>
</mx:Script>
<mx:Label id="lb"/>
<my:custom1 id="id1" width="100" height="30"/>
</mx:Application>
これで、子コンポーネントの Bindable 変数の変化を親コンポーネントで感知する事が出来るようになりました。
Bindable の更新通知の仕組みはイベントで有る事がわかります。
変数が複数あったら・・・
子コンポーネントから子コンポーネントへの情報伝達は、素直に記述できます。custom2.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:HSlider id="xBar" width="100" change="onChangeX()"></mx:HSlider>
<mx:VSlider id="yBar" height="100" change="onChangeY()"></mx:VSlider>
<mx:Script>
<![CDATA[
private function onChangeX():void
{
xSize = xBar.value;
}
[Bindable] public var xSize:Number;
private function onChangeY():void
{
ySize = yBar.value;
}
[Bindable] public var ySize:Number;
]]>
</mx:Script>
</mx:HBox>
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:my="*">
<mx:Label id="lbX" text="{id1.xSize}" />
<mx:Label id="lbY" text="{id1.ySize}" />
<my:custom2 id="id1"/>
</mx:Application>
Flexは、どうやって各プロパティを区別しているのか?
Bindable 変数を持ったコンポーネントの PropertyChangeEvent.PROPERTY_CHANGE を監視すればよいのは判りましたが、変数が複数あった場合、どの変数が変化しても PropertyChangeEvent.PROPERTY_CHANGE が発生します。そこで、PropertyChangeEvent を調べてみると、property という物があるようです。これは、変化&更新のあった変数名を格納しているプロパティです。
→参照:http://www.adobe.com/livedocs/flex/3_jp/langref/mx/events/PropertyChangeEvent.html
前述のコードを以下のように修正し、トレースを観察してみます。
Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:my="*">
<mx:Script>
<![CDATA[
import flash.events.Event;
import mx.events.PropertyChangeEvent;
private function init():void
{
id1.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onChange);
}
private function onChange(e:PropertyChangeEvent):void
{
trace("property=" + e.property.toString());
}
]]>
</mx:Script>
<my:custom2 id="id1"/>
</mx:Application>
プロパティ名の「xSize」「ySize」が動作に応じてトレースされるのがわかると思います。
- PropertyChangeEvent.PROPERTY_CHANGE を監視し、PropertyChangeEvent.property で示されるプロパティ名に応じて処理を振り分ける。
Flex がこのように作られている事から、
→コンポーネントに含まれるBindable変数は少ない方が良い。
→コンポーネントの粒度はより細かい方がよい?(プロパティの数に準ずる
と考える事も出来ますね。
Bindable イベント指定
Bindableは、任意の発行 event を指定が出来るような記述がありますが、 結局自前のコードでイベントを発行しなければなりません。→参照:http://www.adobe.com/livedocs/flex/3_jp/html/help.html?content=databinding_8.html
場合にもよりますが、極論、Bindableを指定する意味が損なわれてしまいます。特にこのサンプルのような場合は、Bindable 指定する意味すらなく、只の public変数で十分です。
custom3.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:HSlider id="xBar" width="100" change="onChangeX()"></mx:HSlider>
<mx:VSlider id="yBar" height="100" change="onChangeY()"></mx:VSlider>
<mx:Script>
<![CDATA[
import flash.events.Event;
private function onChangeX():void
{
xSize = xBar.value;
dispatchEvent(new Event("XEVENT"));
}
[Bindable(event="XEVENT")] public var xSize:Number;
private function onChangeY():void
{
ySize = yBar.value;
}
[Bindable] public var ySize:Number;
]]>
</mx:Script>
</mx:HBox>
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:my="*">
<mx:Script>
<![CDATA[
import flash.events.Event;
import mx.events.PropertyChangeEvent;
private function init():void
{
id1.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onChange);
id1.addEventListener("XEVENT", onChangeX);
}
private function onChange(e:PropertyChangeEvent):void
{
lbY.text = e.newValue.toString();
}
private function onChangeX(e:Event):void
{
lbX.text = id1.xSize.toString();
}
]]>
</mx:Script>
<mx:Label id="lbX"/>
<mx:Label id="lbY"/>
<my:custom3 id="id1"/>
</mx:Application>
この例では、Bindable の event記述をしていますが
[Bindable(event="XEVENT")] は無くても動作に変化はありません。まとめ
Bindable は、「手放しで便利だから使うべき。」「とりあえず使っとけ。」という程の物でもないようです。そこは適材適所、使いよう。例えば「複数のプロパティが更新された際、コンポーネントの内容を描画し直したい」と言う場合、 該当の変数が Bindable 指定されていれば、PropertyChangeEvent.PROPERTY_CHANGE の監視だけで、更新作業を行う事が出来ます。
→参照:http://d.hatena.ne.jp/secondlife/20070326/1174904664
逆に、ガッチリ各プロパティの更新を区別をしたい場合、つまるところ自力での更新イベント実装にした方が良い場合もあります。
Flex コンポーネント作成の際は、本当に Bindable で実装するべきなのかを良く考える必要が有ると言えるでしょう。

コメントする