2008-08-18 23 views
13

私はこれまでFlex開発のビットをやったが、私が収集した(と私が間違っている場合は、私を修正てください!)ので、私は、MXMLファイルの上にコントロールをプログラムで作成するアプローチを優先しましたつまり、クラスの機能を別のActionScriptクラスファイルに入れても、mxmlで宣言されている要素が含まれていることになります。フレックス:プログラム的なデータバインディングは無駄ですか?

は、生産単位の大きな違いがあるように思えませんが、プログラム的に結合やっデータは些細よりもやや少ないようです。 mxmlコンパイラがデータバインディング式をどのように変換するかを見てきました。その結果、生成されたコールバックがたくさんあり、mxml表現よりもはるかに多くの行があります。だからここに質問があります:は、プログラムでデータをバインドする方法はありますか?

答えて

29

は、MXMLを恐れてはいけません。ビューをレイアウトするのに最適です。 再利用可能なコンポーネントを記述してActionScriptで記述すると、制御が少ししかできない場合がありますが、再利用不可能なビューの場合は、MXMLがはるかに優れています。それは、より簡潔だ、バインディングは、セットアップが簡単ですextemelyなど

しかし、純粋なActionScriptでバインディングは、痛みのそれくらいである必要はありません。多くのことが行われているMXMLほどシンプルになることはありませんが、それほど多くの労力を費やす必要はありません。

BindingUtilsとその方法はbindSetterbindPropertyです。ほとんどの場合、前者を使用します。通常は仕事をしたいのですが、値が変わるときにはinvalidatePropertiesに電話してください。ほとんどの場合、プロパティを設定する必要はありません。

あなたが知る必要があることは、これらの2つがタイプChangeWatcherのオブジェクトを返すことです。何らかの理由でバインディングを削除する場合は、このオブジェクトを保持する必要があります。これは、ActionScriptでの手作業のバインディングをMXMLより手軽にするものです。

のは、簡単な例を見てみましょう:

BindingUtils.bindSetter(nameChanged, selectedEmployee, "name"); 

これは設定しているが、メソッドnameChanged呼び出しますバインドするときに、変数selectedEmployee変更内のオブジェクトのプロパティnamenameChangedメソッドは、引数としてnameプロパティの新しい値を受け取るだろう、それは次のようになります。

private function nameChanged(newName : String) : void 

この単純な例での問題は、あなたが設定した後に、このことは、それぞれの時間を発動する結合ということです指定されたオブジェクトのプロパティが変更されます。変数selectedEmployeeの値は変更される可能性がありますが、変数が以前に指し示したオブジェクトに対してバインディングがまだ設定されています。

これを解決するには、2つの方法があります。どちらかがChangeWatcher周りBindingUtils.bindSetterによって返さ維持し、削除するとき、それにunwatchを呼び出すには、結合(と、代わりに新しいバインディングを設定する)、または自分自身に特異的に結合します。私はあなたに最初の選択肢を最初に示し、あなた自身に束縛することによって私が意味することを説明します。

currentEmployeeは(唯一のセッターを示す)ゲッター/セッターのペアに行われ、このように実装することができます

public function set currentEmployee(employee : Employee) : void { 
    if (_currentEmployee != employee) { 
     if (_currentEmployee != null) { 
      currentEmployeeNameCW.unwatch(); 
     } 

     _currentEmployee = employee; 

     if (_currentEmployee != null) { 
      currentEmployeeNameCW = BindingUtils.bindSetter(currentEmployeeNameChanged, _currentEmployee, "name"); 
     } 
    } 
} 

何が起こることはcurrentEmployeeプロパティが設定されている場合、それがあったかどうかを確認するために見えることです新しい値がnullの場合は、nameプロパティの新しいバインドを設定しない限り、プライベート変数を設定します(currentEmployeeNameCW.unwatch())。最も重要なことは、バインディングコールによって返されたChangeWatcherが保存されることです。

これは基本的なバインディングパターンであり、正常に動作すると思います。しかし、少しシンプルにするためのトリックがあります。代わりにあなた自身にバインドすることができます。 currentEmployeeプロパティが変更されるたびにバインディングを設定したり削除したりする代わりに、バインディングシステムで行うことができます。あなたのcreationCompleteハンドラ(またはコンストラクタまたは初期少なくともいくつかの時間)で、あなたがそうのようなバインディングを設定することができます。

BindingUtils.bindSetter(currentEmployeeNameChanged, this, ["currentEmployee", "name"]); 

これはthiscurrentEmployeeプロパティに、だけでなく、nameプロパティにだけでなく、バ​​インディング設定しますこのオブジェクトにだからいつでもどちらかのメソッドを変更するcurrentEmployeeNameChangedが呼び出されます。バインディングを決して削除する必要がないため、ChangeWatcherを保存する必要はありません。

第2の解決策は、多くのケースで動作しますが、私は最初のものは(非表示のクラスでバインディングを扱う場合は特に、時々必要であることを発見したthisは、イベントディスパッチャなければならないとcurrentEmployeeがなければならないので、それが働くためにバインド可能)。

+0

大書込み。これは非常に役に立ちました。ありがとう! – airportyh

+0

本当に偉大な書き込み。 – Kevin

+0

本当に素晴らしい書き込み!簡単な質問。最初のソリューションへのより簡単なアプローチは、単にcurrentEmployeeNameCWがnullであるかどうかを確認することではないでしょうか? nullでなければ、バインディングが存在するので、currentEmployeeNameCW.unwatch()を呼び出します。より一般化された、まだ非常に簡潔な解決策のようです。 – rinogo

2

コンポーネントのMXMLとActionScriptを別々のファイルに分ける1つの方法は、ASP.Net 1.xのコードビハインドモデルと同様のことを行うことです。このモデルでは、宣言部分(この場合はMXML)は、必須部分(ActionScript)のサブクラスです。だから私はこのようなクラスの背後にあるコードを宣言する可能性があります

package CustomComponents 
{ 
    import mx.containers.*; 
    import mx.controls.*; 
    import flash.events.Event; 

    public class MyCanvasCode extends Canvas 
    { 
     public var myLabel : Label; 

     protected function onInitialize(event : Event):void 
     { 
      MyLabel.text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit."; 
     } 
    } 
} 

...と、このようなマークアップは:あなたはこの例からもわかるように

<?xml version="1.0" encoding="utf-8"?> 
<MyCanvasCode xmlns="CustomComponents.*" 
    xmlns:mx="http://www.adobe.com/2006/mxml" 
    initialize="onInitialize(event)"> 
    <mx:Label id="myLabel"/>  
</MyCanvasCode> 

は、このアプローチのdisadvatageです両方のファイルにmyLabelのようなコントロールを宣言しなければならないことに注意してください。

+0

そのようにするのが良い理由は、フレックスデザインビューを壊さないということです。あなたがデザインビュー(私のようなもの)にあまり気にしないなら、他の方法で継承を行うことは、扱いがずっと簡単です。 .asクラスのmxmlの子を事前に宣言する必要はありません。また、それはより "正しい"感じます。ビジュアルを取り、機能を追加します。 –

+0

これを行わないと、ビューに必要なクラスの数が2倍になります。 – Clintm

0

通常、mxmlとアクションスクリプトを一緒に使用する方法があります。すべてのmxmlコンポーネントは、より複雑なコードを追加するアクションスクリプトクラスから継承します。次に、このクラスで実装されているイベントリスナーをmxmlファイルで参照できます。それが今日のように存在する

よろしく、

ルース

8

http://code.google.com/p/bindage-tools

BindageTools BindingUtilsする代わりに、(そこに言葉遊びを参照してくださいされています:)

私はちょうど私のActionScriptデータバインディングプロジェクトとしてオープンソースをリリース?)あなたはパイプラインのスタイルであなたのデータバインディングを宣言流暢APIを使用する:

Bind.fromProperty(person, "firstName") 
    .toProperty(firstNameInput, "text"); 

双方向バインディング:

Bind.twoWay(
    Bind.fromProperty(person, "firstName"), 
    Bind.fromProperty(firstNameInput, "text")); 

明示的なデータ変換と検証:

Bind.twoWay(
    Bind.fromProperty(person, "age") 
     .convert(valueToString()), 
    Bind.fromProperty(ageInput, "text") 
     .validate(isNumeric()) // (Hamcrest-as3 matcher) 
     .convert(toNumber())); 

その他、各種このサイトにはさらに多くの例があります。他にもたくさんの機能があります。 --Matthew

編集:更新されたAPI

+0

それは誰かがこれをしたことを見つけるのはとても素晴らしいです、純粋なas3方法ありがとう〜ありがとう〜 – davyzhang

+0

私の喜び、あなたがそれが有用であるとうれしい。 – qualidafial

関連する問題