0

Flex のバインディングで予期しない動作が発生することに気付きました。私のコードは次のとおりです。

アプリケーションコード

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" horizontalAlign="center" xmlns:Model="Model.*">
    <mx:Script>
        <![CDATA[
            import Model.DataDummy;
        ]]>
    </mx:Script>
    <mx:HBox width="100%" horizontalGap="30">
        <mx:Button id="buttonChange1" label="Change property value" click="myDummy._resetMyProperty();" />
        <mx:Label id="labelRaw" text="{'My Property=' + myDummy.MyProperty}" opaqueBackground="#DDDDDD" />
        <mx:Label id="labelFormatted" text="{'My Property formatted=' + myDummy.MyPropertyFormatted}" opaqueBackground="#DDDDDD" />
    </mx:HBox>

    <Model:MyDummy id="myDummy" />

    <mx:DataGrid id="dataGrid"
         width="100%" dataProvider="{DataDummy.Dummies}">
        <mx:columns>
            <mx:DataGridColumn dataField="MyProperty" headerText="My property" />
            <mx:DataGridColumn dataField="MyPropertyFormatted" headerText="My property Formatted" />
        </mx:columns>
    </mx:DataGrid>
    <mx:Button id="buttonChange2" click="{for each ( var d:MyDummy in DataDummy.Dummies ){d._resetMyProperty();}}" label="Change property value in DataGrid" />
</mx:Application>

Model.MyDummy クラス コード

package Model
{
    import flash.events.EventDispatcher;

    import mx.formatters.NumberFormatter;
    import mx.utils.StringUtil;

    [Bindable]
    public class MyDummy extends EventDispatcher
    {
        /*** Constructor ***/
        public function MyDummy()
        {
            this._resetMyProperty();
        }

        /*** Properties ***/
        private var _myProperty:Number;
        public function get MyProperty():Number
        {
            return _myProperty;
        }
        public function set MyProperty(value:Number):void
        {
            if ( value !== _myProperty )
            {
                _myProperty = value;

                //var event:Event = new Event("ID_Changed");
                //this.dispatchEvent(event);
            }
        }

        //[Bindable (event="ID_Changed", type="flash.events.Event")]
        public function get MyPropertyFormatted():String
        {
            var idFormatted:String = "";

            if ( ! isNaN(this.MyProperty) )
            {
                var formatter:NumberFormatter = new NumberFormatter();
                formatter.precision = 2;
                idFormatted = formatter.format(this.MyProperty);
            }
            else
                idFormatted = MyProperty.toString();

            return StringUtil.substitute( "{0} (My property has been formatted)", idFormatted );
        }

        /*** Methods ***/
        public function _resetMyProperty():void
        {
            this.MyProperty = Math.round(Math.random() * 1000000000);
        }
    }
}

Model.DataDummy クラス コード

package Model
{
    import mx.collections.ArrayCollection;

    public class DataDummy
    {
        private static var _dummies:ArrayCollection;
        public static function get Dummies():ArrayCollection
        {
            if ( _dummies == null )
            {
                _dummies = new ArrayCollection();
                _dummies.addItem(new MyDummy());
                _dummies.addItem(new MyDummy());
            }

            return _dummies;
        }
    }
}

動作は次のとおりです。

  • buttonChange1 をクリックすると、インスタンス myDummy で _resetMyProperty が呼び出されます。

    その結果、ラベル「labelRaw」のテキストは変更され、ラベル「labelFormatted」のテキストは変更されません。これは、Flex のドキュメントによると、MyPropertyFormatted が読み取り専用プロパティであり、その読み取り専用プロパティがアプリケーションの初期化時にのみバインドされ、その後ではバインドされないために発生します。これで、私は同意します。


  • buttonChange2 をクリックすると、ArrayCollection Model.DataDummy.Dummies のすべての MyDummy 要素で resetMyProperty メソッドが呼び出されます (この静的プロパティは DataGrid にバインドされます)。

    その結果、DataGrid の 2 番目の列が MyDummy オブジェクトの同じ読み取り専用プロパティ MyPropertyFormatted にリンクされているにもかかわらず、DataGrid の両方の列の値が変更されます。これは、私が説明した以前の動作と矛盾していると思います。

私のポイントは次のとおり
です。 1. 一方では、コントロールを特定のオブジェクトの単一のインスタンスにバインドしているため、バインドは彼の読み取り専用プロパティでトリガーされません。
2.一方、同じ特定のオブジェクトのコレクションにコントロールをバインドすると、すべてのプロパティ (読み取り専用かどうかに関係なく) でバインドがトリガーされます。

ポイント1の読み取り専用プロパティでバインディングをトリガーする場合は、イベントをディスパッチし、読み取り専用プロパティのMetaTagで、このイベントに従ってバインディングがトリガーされることを正確にする必要があります(クラスModelのコードのコメントを示すように) .MyDummy クラス)。

この動作が異なるのはなぜですか? ArrayCollection インスタンスのバインディングが何を行い、単一のインスタンスのバインディングが何を行わないかを正確に理解したいと思います。

ご協力ありがとうございました。

4

1 に答える 1

2

正しいコードは次のようなものだと思います。

まず、私たちのmodel.MyDummyクラス:

package model
{
import flash.events.EventDispatcher;

import mx.events.PropertyChangeEvent;
import mx.formatters.NumberFormatter;
import mx.utils.StringUtil;

public class MyDummy extends EventDispatcher
{

    //------------------------------------------------------------------------------
    //
    //   Constructor 
    //
    //------------------------------------------------------------------------------

    public function MyDummy()
    {
        resetMyProperty();
    }

    //------------------------------------------------------------------------------
    //
    //   Properties 
    //
    //------------------------------------------------------------------------------

    //--------------------------------------
    // myProperty 
    //--------------------------------------

    private var _myProperty:Number;

    [Bindable(event="propertyChange")]
    public function get myProperty():Number
    {
        return _myProperty;
    }

    public function set myProperty(value:Number):void
    {
        if (_myProperty == value)
            return;
        var oldPropertyValue:Number = _myProperty;
        var oldFormatted:String = myPropertyFormatted;
        _myProperty = value;
        dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, "myProperty", oldPropertyValue, value));
        dispatchEvent(PropertyChangeEvent.
            createUpdateEvent(this, "myPropertyFormatted", oldFormatted, myPropertyFormatted));
    }

    [Bindable(event="propertyChange")]
    public function get myPropertyFormatted():String
    {
        var idFormatted:String = "";

        if (!isNaN(myProperty))
        {
            var formatter:NumberFormatter = new NumberFormatter();
            formatter.precision = 2;
            idFormatted = formatter.format(myProperty);
        }
        else
            idFormatted = myProperty.toString();

        return StringUtil.substitute("{0} (My property has been formatted)", idFormatted);
    }

    //------------------------------------------------------------------------------
    //
    //   Methods 
    //
    //------------------------------------------------------------------------------

    public function resetMyProperty():void
    {
        myProperty = Math.round(Math.random() * 1000000000);
    }
}
}

イベントを発生させて、私たちからpropertyChange発生する可能性があります(イベントを自動的にリッスンします)。collectionChangeEventArrayCollectionpropertyChange

次に、私たちのmodel.DataDummyクラス:

package model
{
import mx.collections.ArrayCollection;
import mx.events.CollectionEvent;

public class DataDummy
{

    //------------------------------------------------------------------------------
    //
    //   Constructor 
    //
    //------------------------------------------------------------------------------

    public function DataDummy()
    {
        dummies = new ArrayCollection();
        dummies.addItem(new MyDummy());
        dummies.addItem(new MyDummy());
    }

    //------------------------------------------------------------------------------
    //
    //   Variables 
    //
    //------------------------------------------------------------------------------

    [Bindable]
    public var dummies:ArrayCollection;
}
}

メタタグを使用したデータ バインディングの利点を得るために静的を使用しません[Bindable]

そして最後に、変更を最小限に抑えたメイン クラス:

<mx:Application horizontalAlign="center" layout="vertical" xmlns:model="model.*" xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script>
    <![CDATA[
        //------------------------------------------------------------------------------
        //
        //   Event Handlers 
        //
        //------------------------------------------------------------------------------

        protected function buttonChange2_clickHandler(event:MouseEvent):void
        {
            for each (var d:MyDummy in dataProvider.dummies)
            {
                d.resetMyProperty();
            }
        }
    ]]>
    </mx:Script>
    <mx:HBox horizontalGap="30" width="100%">
        <mx:Button click="myDummy.resetMyProperty();" id="buttonChange1" label="Change property value" />
        <mx:Label id="labelRaw" opaqueBackground="#DDDDDD" text="{'My Property=' + myDummy.myProperty}" />
        <mx:Label id="labelFormatted" opaqueBackground="#DDDDDD"
            text="{'My Property formatted=' + myDummy.myPropertyFormatted}" />
    </mx:HBox>

    <model:MyDummy id="myDummy" />
    <model:DataDummy id="dataProvider" />

    <mx:DataGrid dataProvider="{dataProvider.dummies}" id="dataGrid" width="100%">
        <mx:columns>
            <mx:DataGridColumn dataField="myProperty" headerText="My property" />
            <mx:DataGridColumn dataField="myPropertyFormatted" headerText="My property Formatted" />
        </mx:columns>
    </mx:DataGrid>
    <mx:Button click="buttonChange2_clickHandler(event)" id="buttonChange2" label="Change property value in DataGrid" />
</mx:Application>

ご覧のとおり、すべてのバインディングが期待どおりに機能します。

PS[Bindable(event="propertyChange")]は simple と同等ですが、この方法でgetter[Bindable]に関するコンパイラの警告を回避できます。myPropertyFormatted実際には、単純な[Bindable]形式を使用すると、mxmlcコンパイラはdispatchEventコードを自動的に生成します。[Bindable]また、タグで特定のイベントを指すことを使用して、より詳細に制御できます。たとえば、この場合、 のイベントを発生させることができmyPropertyFormattedます。

PPS 実際の ActionScript/MXML のものを反映するために、C# のような命名規則を変更しました。

于 2011-05-04T12:00:52.163 に答える