我注意到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>
模型。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);
}
}
}
模型。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, _resetMyProperty在实例myDummy上被调用。
结果是标签"labelRaw"的文本被更改,而标签"label格式化"的文本没有被更改。根据Flex文档,这确实发生了,因为myproperty格式化是一个只读属性,只读属性仅在应用程序初始化时绑定,而不是之后。对此,我同意。// - 当我点击buttonChange2时,resetMyProperty方法在ArrayCollection model . datadmy . dummies的每个MyDummy元素上被调用(这个静态属性被绑定到DataGrid)。
结果是 DataGrid的两列的值都改变了,尽管DataGrid的第二列链接到MyDummy对象的相同只读属性myproperty格式化。我发现这与我之前描述的行为不一致。
我的观点是:
1. 一方面,因为我将控件绑定到某个对象的单个实例,所以绑定不会触发它的只读属性。
2. 另一方面,当我在同一特定对象的集合上绑定控件时,绑定将触发每个属性(只读或非只读)。
如果我想在第1点触发对只读属性的绑定,我必须调度一个事件,并在只读属性的MetaTag上精确地表示它们的绑定将根据该事件被触发(如类Model代码中的注释所示)。MyDummy类).
为什么这种行为不同?我想准确地理解ArrayCollection实例的绑定做了什么,而单个实例的绑定没有。
谢谢你的帮助。
我想正确的代码应该是这样的:
首先是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
事件,以便有可能从ArrayCollection
中触发collectionChangeEvent
(它会自动侦听propertyChange
事件)。
然后我们的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>
正如你所看到的,所有的绑定都能正常工作。
注:[Bindable(event="propertyChange")]
相当于简单的[Bindable]
,但这样可以避免myPropertyFormatted
getter上的编译器警告。实际上,使用简单的[Bindable]
形式会导致mxmlc
编译器自己生成dispatchEvent
代码。您可以使用指向[Bindable]
标记中的特定事件来获得更多控制。例如,在本例中,我们可以为myPropertyFormatted
触发事件。
P.P.S.我已经改变了你的c#类命名约定,以反映实际的ActionScript/MXML的