MXMLとロジックの分離

MXML中にActionScriptのロジックを埋めるのはイヤなものです。そんなにコードが汚くなるんならMXMLなんか要らない!という人も多いのではないでしょうか?

現在、ロジック部分をMXMLファイルから分離するにはいくつかの方法があります。

1)単純にソースを分離する
C#なんかと同じように、Script部分を別ファイルに書くことができます。MXMLと同じ名前が使えないのは難点ですが(MXMLとASを同じ階層においた場合)、コンポーネントによけいなサフィックスを付加することなくアクセスできるのでキレイといえばこれが一番キレイかもしれません。

2)IMXMLObjectを実装したロジッククラスを埋め込む
IMXMLObjectを継承したオブジェクトは、そのままMXMLにタグとして埋め込むことが出来ます。initialize()メソッドを実装するときに引数として親コンポーネントが渡ってくるので、ソース側ではこれを参照することが出来ます。

3)CairngormフレームワークのViewHelperを使う
Cairngormフレームワークに収録されたViewHelperはIMXMLObjectの実装のひとつで、これでインスタンス化されたオブジェクトは、ViewLocatorという別のクラスから一元的に管理されます。
フローティングダイヤログを多用するプロジェクトの場合に大変便利なのですが、一方で、ロジックのインスタンスをひとつしか作成できないという不便さがあります。

4)YuiFrameworkを使う
これもIMXMLObjectの実装のひとつで、デザイナとプログラマとの分業を目的としています。まだ使ったことがありませんが、コードの自動生成などを備えているようで、慣れれば便利そうです。


埋め込みロジックの役割は以下のようなものです。

1)コンポーネント間のデータバインディング
MXML内でバインディングを指定するほうがてっとり早い場合が多いですが、デザイン編集中に消えてしまいがちなので、初期化の段階でBindingUtilsを使って結び付けます。

2)コンポーネント全体が保持すべきデータモデルの局所化
パネル全体で設定されたデータをモデルにぶち込んだりするロジックを書きます。

3)入力エラーなどの処理

4)新たなポップアップの管理 ・・・など。


Flexはイベントドリブンなので、ロジックオブジェクトを複数埋め込むと、どちらのロジックも実行されます。
つまり、同じパーツをもつ複数のデザインのダイヤログがある場合、パーツの役割に応じてロジックをまとめることが出来ます。
たとえば、入力1と2を持つダイヤログ1と、入力2と3を持つダイヤログ2がある場合、入力2に関するロジックは共通化可能ですよね?
それに、ダイヤログ1ではフォームを縦に並べたいが、ダイヤログ2では横に並べたい、といった場合にもロジックが共通化されていると便利です。
(ただし代償として、ロジック側はMXMLに埋め込まれた各コンポーネントの型とIDを知っておく必要があります。初期化時にチェックできるよう、メタ情報を振っておくべきですね)


IMXMLObjectの初期化処理を使う際の注意点です。

initialize()メソッドが走るタイミングはコンポーネント側でinitialize()が走っているときです。なので、Bindingなどの処理を行うには、ここでさらにdocumentに対してcreationCompleteイベントハンドラを定義して、その中で実行させることになります。documentの内部コンポーネントインスタンス化されていないからです。

ところが、このタイミングでも内部コンポーネントインスタンス化されていない場合があります。
その具体例がTabNavigatorなどViewStackに関連するものです。TabNavigatorの場合、初期化段階でアクティブでないタブ内のコンポーネントに関しては、その内部までインスタンス化しないようになっています。
なので、creationCompleteよりもFlexEvent.SHOWを拾うようにする必要があります。

共通の設定項目が散在する大量のダイヤログがあり、さらにそれらのサンプル表示も伴うような場合に、このような実装は結構有効です。