2008/12/19

labelFunctionかItemRendererか。それとあとFormatter (3)

前回の続き。

「動的に1000単位とかに切り替えられる仕組み」に挑戦中なわけですが、ここで「動的に」といっているのは、前回のVariableCurrencyFormatterの、「表示単位」を


<formatters:VariableCurrencyFormatter id="formatter" unit="{int(rbtnGrp.selectedValue)}"/>
<mx:RadioButtonGroup id="rbtnGrp" selectedValue="1000" />
<mx:HBox>
<mx:RadioButton group="{rbtnGrp}" label="(1)" value="1" />
<mx:RadioButton group="{rbtnGrp}" label="(千)" value="1000" selected="true" />
<mx:RadioButton group="{rbtnGrp}" label="(百万)" value="1000000" />
</mx:HBox>


という感じで変えてやりたい、ということです。
上記だと、ラジオボタンを選べばその単位になってほしい、というところ。

ここまでだと、確かに VariableCurrencyFormatter のunitプロパティは、データバインディングがうまくはたらいてラジオボタンの選択した値になってくれます。
これを、


<mx:DataGridColumn dataField="int1" labelFunction="{formatter.format}" textAlign="right"/>


と書いたlabelFunctionまで伝搬させてあげたいわけです。


というところで、関数も第一級のオブジェクトとして、つまりは変数として扱えるActionScriptの性質を利用してやればできるんじゃないかなぁと思ってみた。
変数の値が変わればいいので、強引に関数オブジェクトを入れ替えれてやればいいだろうと。

で、unitが変わったら関数オブジェクトを入れ替えてやるので、


private var _unit:int = UNIT_ONE;

[Bindable]
public function get unit():int { return _unit; }
public function set unit(value:int):void
{
_unit = value;
this.format = null;
this.format = formatFunction;

}

[Bindable]
public var format:Function = formatFunction;

private function formatFunction(item:Object, column:DataGridColumn):String
{
var dat:Object = item;

if (column != null && item.hasOwnProperty(column.dataField))
{
dat = item[column.dataField];
}

var curFormatter:CurrencyFormatter = new CurrencyFormatter();

return curFormatter.format(Number(dat) / unit);
}


とやってみた。。。


まぁ、少々強引だけれども、確かに意図したとおりに動くは動くみたい。
format プロパティに一度nullをセットしているのは、どうもデータバインディングは同じ参照が渡されてもバインディング先に通知されないから。


なんとも美しくないのと、format プロパティがpublicなので外からトンデモナイものをセットされないとも限らない、というのが怖いので、次のステップはこれを何とかしてみたい。