kagamihogeの日記

kagamihogeの日記です。

yui-frameworks さわってみた

20090411 追記ここから

※検索エンジンなどからこのエントリにたどり着かれた方へ。

本エントリで触れている yui-framewoks は古いバージョンを対象にしたものです。今日現在リリースされているバージョンの使用に関しては、本エントリの内容は役に立ちません。ウチの blog なら yui-frameworks の Beta 版さわってみた - kagamihogeのblog を参照して下さい。また、@IT の解説記事がよくまとまっているのでそちらも参考になるかと思います。
Flex/AIR開発でデザイナとの協業を楽にする「yui」(1/3) - 特集:デザイナとプログラマを“結”ぶオープンソース(前編)- @IT

yuiを使ったFlexアプリを作って、便利さを体感しよう(1/4) - 特集:デザイナとプログラマを“結”ぶオープンソース(後編)- @IT

20090411 追記ここまで



AKABANA - yui-frameworks(ゆい) - Flex2 framework をさわってみた。なにげに紛らわしいが YUI Library とはベツモノ。

Eclipse3.3 + Flex Builder 3 plugin を前提にしています。

yui-frameworks ライブラリの配置

まず Flex プロジェクトを作成しておく。

AKABANA - downloads から akabana.yui-frameworks を DL する。解凍してできたディレクトリ中の yui-frameworks/target/swc/yui-frameworks.swc と yui-frameworks/src/main/resources/yui-metadata-config.xml を libs ディレクトリにコピーする。libs はライブラリパスのディレクトリ。Eclipse 上だと libs がデフォルトになってる。

プロジェクト右クリック -> プロパティ -> Flex コンパイラ の 追加コンパイラ引数に下記の項目を追記する。libs のディレクトリを別にしてる場合は適宜読み替えで。


-load-config+=../libs/yui-metadata-config.xml

yui-frameworks の威力を体験してみる

テキストフィールドとボタンをひとつ備えた画面を作る。テキストフィールドに何か入力するとその値がコンソールに表示され、ボタンを押すとテキストフィールドがある値に更新される……というものを作る。

yui-framworks の謳っている、ViewとLogicの分離・Convention over Configuration・メタデータを用いたDI・双方向バインディング、を一通り体験するのが目的。サーバーサイドとの連携、はよくわからんかったのでスルー。

まず src/view, src/logic, src/dto ディレクトリを作成する。src はメインソースフォルダ。環境違うなら適宜読み替えよろしく。view には MXML コンポーネント、logic には各 MXML コンポーネントに対応するイベントハンドラなどのロジックを格納する ActionScript クラス、dto にはデータバインディング用の ActionScript クラスを配置することになる。ちなみに、ディレクトリ名は別になんでもいい。

src/view に TestView.mxml という MXML コンポーネントを作成する。中身はこんな感じ。





なんてことない mxml です。

次に、src/logic に TestViewLogic.as という ActionScript クラス、src/dto に TestDto.as という ActionScript クラスを作成する。中身はあとでいじる。

main.mxml の中身をぜんぶ消して下のように書き換える。





肝要な点がいくつか。

まず mx:Appication を yui:YuiApplication に変更。これでこの mxml が yui-frameworks の管理下に入る。で、さっき作成した 3 ファイルを配置する。yui-framworks はこのコンポーネントに割りあてた id を使ってお互いに参照できるような関連付けをする。

この id の命名規則が重要になるんだけど、なにぶん公式ドキュメントが見当たらないわけでして…… id の命名規則に関しては が詳しい。

まとめると「現段階の yui-frameworks 」では view となる mxml の id は *View に、logic となる ActionScript クラスの id は *ViewLogic にしないとダメ、とのこと。ちなみに dto は命名に縛りはない様子。クラス名はたぶんなんでもいいのかな?

それはさておき続き。TestViewLogic.as にイベントハンドラなどを作成する。


public class TestViewLogic {
[View]
public var testView:TestView;

public function hogeButtonClickHandler(event:MouseEvent):void {
trace("hogeButton no Label=" + testView.hogeButton.label);
}
}

[View] を付けた public var testView:TestView; と定義することで TestViewLogic と TestView が自動で関連付けられる。TestView クラスの変数名は main.mxml で定義した id つまり testView にしなければならない。

で hogeButtonClickHandler だが、こいつが TestView の hogeButton が click されたときのイベントハンドラとして自動で関連付けられる。[コンポーネント名 + イベント名 + Handler] という命名規則でメソッドを作ると、指定したコンポーネントのイベントにイベントハンドラが関連付けられる。この例でいくと、TestView.mxml に hogeButton という id の Button がある。なので hogeButtonClickHandler というメソッドを作ると、このメソッドが hogeButton を click したときのイベントハンドラとして自動で登録される。

もうひとつイベントハンドラを追加してみる。

TestView.mxml にある textInputHoge という id の TextInput コンポーネントの change イベントハンドラを作りたい場合は下のようなメソッドを TestViewLogic に追加する。


public function textInputHogeChangeHandler(evenet:Event):void {
trace("textInputHoge changed");
}

ビルドしてデバッグモードで実行して、ボタン押すとなんかコンソールに流れて、テキストフィールドになんか入力されるとコンソールになんか流れる、はず。

とまぁ、こんな感じに TestView.mxml を 1 ミリもいじらずにイベントハンドラを定義できるのが yui-frameworks のすごい点。

次に双方向バインディングのコードを追加する。

TestViewLogic クラスに下記のプロパティ定義を追加する。


[Model(bindView="testView")]
public var testDto:TestDto;

このコードは TestView.mxml と TestDto クラスのプロパティが双方向バインディングするためのもの。[Model] で testDto を yui-framworks が扱えるようにして、bindView でバインド先の mxml を指定する。

TestDto をこんな感じのコードにする。ちなみに class に [Bindable] を付けないとバインディングが View -> Dto の片道になる。


[Bindable]
public class TestDto {
public var textInputHoge:String;
}

TestDto に textInputHoge という名前のプロパティを作ることで、TestView.mxml の textInputHoge という id がつけられた TextInput コンポーネントと関連付けが行われる。要はコンポーネントの id と Dto の public プロパティ変数名を同じにするのが重要、ということ。

この状態で TestViewLogic を下記のように書き換えてみる。


public function hogeButtonClickHandler(event:MouseEvent):void {
trace("hogeButton no Label=" + testView.hogeButton.label);
testDto.textInputHoge = "hogeButtonClickHandler";
}

public function textInputHogeChangeHandler(evenet:Event):void {
trace("textInputHoge changed[" + testDto.textInputHoge + "]");
}

これで実行。hogeButton をクリックすると textInputHoge テキストフィールドの入力値が "hogeButtonClickHandler" に更新される。textInputHoge テキストフィールドに何か値を打ち込むと更新された値がコンソールに流れる、ようになるはず。

Flex のデータバインディングは元からかなり強力なんだけど、双方向バインディングしようとするとちょっとめんどい。その辺のメンドウを取り払ってくれるのも yui-frameworks のすごい点。

双方向バインディングはまだ未完成?

Tree や DataGrid はどうなのかな? と思ったけどやり方わからんかったのでボタンのラベルはどうなのかな、とこんなのを TestDto に追加してみた。


public var hogeButton:String="hogeLabel";

しかし例外吐く。

なのでソースをのぞいてみると src/main/actionscript/org/seasar/akabana/yui/framework/customizer/AutoBindingDefaultProperty.xml といういかにもな怪しい設定ファイルがあり、中身はこんな感じ。



text

TextInput しかできないのかな? との予感がする。

次に org.seasar.akabana.yui.framework.customizer.AutoBindingDefaultPropertyResolver を見てみる。


public static function getBindingPropertyName( componentName:String ):String {
var propertyName:String = null;
var components:XMLList = bindingPropertyXml.component.(@name == componentName);
if( components.length() > 0 ){
propertyName = components[0].children()[0].toString();
}
return propertyName;
}

このメソッドの引数 componentName は TextInput とか Button とかのコンポーネント名が渡されてくるっぽい。で、その名前が先の AutoBindingDefaultProperty.xml 中にあるかどうか探し、あったら値を返し、なければ null を返す。なので TextInput 以外は必ず null になる。

で、このメソッドを呼び出してる場所のコードはこんな感じ。


for each( var fieldXml:XML in fieldsXMLList){
varName = fieldXml.@name.toString();
if( view.hasOwnProperty(varName) ){
component = view[ varName ];
bindName = AutoBindingDefaultPropertyResolver.getBindingPropertyName(component.className);
BindingUtils.bindProperty( component, bindName, model, varName);
BindingUtils.bindProperty( model, varName, component, bindName);
}
}

mxml の各フィールドを見て Dto に名前が対応するフィールドがあれば互いにバインド。バインドするとき、コンポーネントのどのプロパティにバインドするか? を AutoBindingDefaultPropertyResolver.getBindingPropertyName から取得するわけだが、これが前述のとおり TextInput のときしか有効な値を返してくれない。

なので、タブン AutoBindingDefaultProperty.xml に下のような定義を追加すればいいのだと思われる。ちなみに実際に試したわけではない。


label

Button のラベルが双方向バインディングできてもアンマリうれしくはないが…… AutoBindingDefaultProperty.xml に Default なんて名前ついてるから、コンポーネントのどのプロパティにバインドさせるか任意に決められるようにでもなる予定なのかな?

なんというか

S2Flex2 と yui-frameworks をちょっと触ってみて思うのは Seasar2 関連プロダクトのドキュメントがぜんぜん無いのがすごくつらい…… yui-frameworks はすごい便利なんだけど、公式ドキュメントに命名規則のルール表が無いと、なんというか、手探りで開発してるみたいでちと怖い。こういう状況だと、上司とかお客さんとかに、「これ使いましょうよ!」って言っても情報の無さから敬遠されがちなのよね……