フレックス:苦痛のないプログラムによるデータ バインディングは存在しますか?

StackOverflow https://stackoverflow.com/questions/14247

質問

私はこれまで Flex 開発を少ししか行っていませんが、mxml ファイルよりもプログラムでコントロールを作成するアプローチを好みました。 お願いします, 間違っていたらごめんなさい!) 両方の方法で使用することはできない、つまり、クラス機能を別の ActionScript クラス ファイルに保持し、含まれる要素を mxml で宣言することはできないことがわかりました。

生産性の点では大きな違いはないようですが、データ バインディングをプログラムで実行するのは簡単ではないようです。mxml コンパイラーがデータ バインディング式をどのように変換するかを調べました。結果として、生成されたコールバックの束と、mxml 表現よりもはるかに多くの行が生成されます。そこで質問は次のとおりです。 大きな損害を与えずにプログラムでデータ バインディングを行う方法はあるでしょうか?

役に立ちましたか?

解決

MXML を恐れる必要はありません。ビューをレイアウトするのに最適です。自分で書く場合 再利用可能 コンポーネントを ActionScript で記述すると、もう少し制御できる場合がありますが、再利用できないビューの場合は MXML の方がはるかに優れています。より簡潔で、バインディングのセットアップも非常に簡単です。

ただし、純粋な ActionScript でのバインディングは、それほど面倒である必要はありません。多くのことが自動的に行われる MXML ほど単純ではありませんが、それほど手間をかけずに実行できます。

あなたが持っているものは BindingUtils そしてそれはメソッドです bindSetter そして bindProperty. 。私は通常、何らかの仕事をしたり、電話をかけたりしたいので、ほとんど常に前者を使用します。 invalidateProperties 値が変更されたときに、単にプロパティを設定したいということはほとんどありません。

知っておく必要があるのは、これら 2 つは次の型のオブジェクトを返すということです。 ChangeWatcher, 、何らかの理由でバインドを削除したい場合は、このオブジェクトを保持する必要があります。このため、ActionScript での手動バインディングは MXML での手動バインディングよりも少し不便になります。

簡単な例から始めましょう。

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

これにより、メソッドを呼び出すバインディングが設定されます。 nameChanged いつ name 変数内のオブジェクトのプロパティ selectedEmployee 変化します。の nameChanged メソッドは、の新しい値を受け取ります 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 プロパティが設定されている場合、以前の値が存在するかどうかを確認し、存在する場合はそのオブジェクトのバインディングを削除します(currentEmployeeNameCW.unwatch())、プライベート変数を設定します。ただし、新しい値が null の新しいバインディングをセットアップします name 財産。最も重要なことは、 ChangeWatcher バインディング呼び出しによって返されます。

これは基本的なバインディング パターンであり、うまく機能すると思います。ただし、もう少し簡単にするために使用できるトリックがあります。代わりに自分自身にバインドすることもできます。毎回バインディングをセットアップしたり削除したりするのではなく、 currentEmployee プロパティを変更するには、バインディング システムに変更を行わせることができます。あなたの中で creationComplete ハンドラー (またはコンストラクター、または少なくとも少し前の時点) では、次のようにバインディングを設定できます。

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

これにより、バインディングが設定されるだけでなく、 currentEmployee のプロパティ this, 、だけでなく、 name このオブジェクトのプロパティ。したがって、メソッドを変更するたびに currentEmployeeNameChanged 呼ばれます。保存する必要はありません ChangeWatcher バインディングを取り外す必要がないからです。

2 番目の解決策は多くの場合に機能しますが、特に非ビュー クラスでバインディングを操作する場合には、最初の解決策が必要になる場合があることがわかりました。 this イベントディスパッチャである必要があり、 currentEmployee 機能するにはバインド可能である必要があります)。

他のヒント

それは今日現在も存在します。:)

ActionScript データ バインディング プロジェクトをオープン ソースとしてリリースしました。 http://code.google.com/p/bindage-tools

BindageTools は、パイプライン スタイルでデータ バインディングを宣言する流暢な API を使用する BindingUtils (言葉遊びを参照してください) の代替品です。

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()));

等。サイトには他にもたくさんの例があります。他にもたくさんの機能がありますので、ぜひご覧ください。--マシュー

編集:更新された API

コンポーネントの 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>

この例からわかるように、このアプローチの欠点は、次のようなコントロールを宣言する必要があることです。 私のラベル 両方のファイルにあります。

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

よろしく、

ルース

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top