今天碰到了一个非常让我困扰的问题,使我觉得很有必要对Object的可绑定代理对象ObjectProxy做一个单独的说明;而<fx:Model>,在编译时正是会被编译为ObjectProxy类型(The most common type of MXML-based model is the <fx:Model> tag, which [b][color=red]is compiled into an ActionScript object of type mx.utils.ObjectProxy[/color][/b], which contains a tree of objects when your data is in a hierarchy, with no type information. The leaves of the Object tree are scalar values)。
关于数据绑定的帖子导航:
[url]http://wuaner.iteye.com/blog/1056650[/url]
关于 [color=red][b]warning: unable to bind to property 'cntCt' on class 'Object' (class is not an IEventDispatcher)[/b][/color] 导航:
[url]http://wuaner.iteye.com/blog/1054153[/url]
问题描述:
两个级联弹出的模态窗口TitleWindow;一级窗口中有名为counterDg的datagrid,其dataProvider为名为counterAC的arrayCollection。二级窗口对一级窗口中的counterDg中数据做增删改(实际就是对counterDg的dataProvider counterAC做增删改;这里的增删改,并不会提交后台,在一级窗口被提交后才会做提交后台的动作)。最开始时,[b]counterAC中存的是Object[/b]。
问题就出在二级窗口中对一级窗口counterDg[color=red][b]做修改的时候[/b][/color]:
改的时候是需要将数据带到二级窗口的,自然一级窗口counterDg.selectedItem会有向二级窗口输入域的单向绑定(这里不应该用双向绑定,因为双向绑定的话,在二级窗口中对绑定的数据做修改,会立即触发一级窗口dataGrid中当前选定行随之而改变,即使你连“提交”按钮都没点;这显然是不合逻辑的。),如:
在二级窗口点击提交按钮的方法中,集中做反向的绑定工作:使用BindingUtils动态的将页面输入域的值绑定回counter:
明明警告我说“不能绑定Object的属性xxx”,却还绑定成功了;刚要以为这个警告无关紧要,却发现绑定仅仅对counterAC起了作用,可是却不会刷新使用counterAC作为dataProvider的counterDg,这算什么个事啊。。。
既然有这样的问题存在,那就从警告入手,着手解决。通过将counterAC中放ObjectProxy对象而不是放Object对象,来解决掉这个警告:
增加时,通过addItem加到一级页面counterAC中的也应该是ObjectProxy:[quote]//二级页面中:
至此,问题解决,一级页面dataGrid在二级页面点击确定后被成功刷新,也没有了刚才的警告。
明白了一个道理:flex中的warning不比error影响力小!千万不能置之不理!
[color=red][size=medium][b]关于ObjectProxy:
Using Flex 4.5 / Using data-driven UI components / Storing data
-> Defining a data model:
[url]http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7b51.html#WS2db454920e96a9e51e63e3d11c0bf66ba1-7ffb[/url][/b]
[/size][/color][quote]The most common type of MXML-based model is the <fx:Model> tag, [color=red]which is compiled into an ActionScript object of type mx.utils.ObjectProxy[/color], which contains a tree of objects when your data is in a hierarchy, with no type information. The leaves of the Object tree are scalar values. Because models that are defined in <fx:Model> tags contain no type information or business logic, you should use them only for the simplest cases. Define models in ActionScript classes when you need the typed properties or you want to add business logic.[/quote]
[color=red][size=medium][b] -> Using a data model as a value object:
[url]http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf66ba1-7ff7.html[/url][/b]
[/size][/color]
[color=red][size=medium][b]under the hood flex data model using the fx:model and fx:xml tags:
[url]http://elromdesign.com/blog/2009/07/20/under-the-hood-flex-data-model-using-the-fxmodel-and-fxxml-tags/[/url][/b]
[/size][/color]
通过remoteObject调用后台得到的result也可能本身就是ObjectProxy类型的,只要:
[url]http://tech.groups.yahoo.com/group/flexcoders/message/66621[/url][quote]You'll have to determine why an ObjectProxy is being created... typically [b]it's because an anonymous Object was returned and RemoteObject had makeObjectsBindable="true" [/b](which it is by default).[/quote]我的返回结果为ObjectProxy的例子:[quote]java后台,返回类型是Map:
使用ObjectProxy时有个注意事项:
[url]http://www.smithfox.com/?e=96[/url][quote]只能处理当前所代理类的直接属性, 不能感知nested field property变化, 这明显和它声明实现IPropertyChangeNotifier接口是不符的.[/quote]
关于数据绑定的帖子导航:
[url]http://wuaner.iteye.com/blog/1056650[/url]
关于 [color=red][b]warning: unable to bind to property 'cntCt' on class 'Object' (class is not an IEventDispatcher)[/b][/color] 导航:
[url]http://wuaner.iteye.com/blog/1054153[/url]
问题描述:
两个级联弹出的模态窗口TitleWindow;一级窗口中有名为counterDg的datagrid,其dataProvider为名为counterAC的arrayCollection。二级窗口对一级窗口中的counterDg中数据做增删改(实际就是对counterDg的dataProvider counterAC做增删改;这里的增删改,并不会提交后台,在一级窗口被提交后才会做提交后台的动作)。最开始时,[b]counterAC中存的是Object[/b]。
问题就出在二级窗口中对一级窗口counterDg[color=red][b]做修改的时候[/b][/color]:
改的时候是需要将数据带到二级窗口的,自然一级窗口counterDg.selectedItem会有向二级窗口输入域的单向绑定(这里不应该用双向绑定,因为双向绑定的话,在二级窗口中对绑定的数据做修改,会立即触发一级窗口dataGrid中当前选定行随之而改变,即使你连“提交”按钮都没点;这显然是不合逻辑的。),如:
<!-- 切记这里不适合配双向绑定 @{counter.cntOt} -->
<mx:FormItem label="开放时间:">
<myDateTime:DateTimeSelectorFinal id="cntOt" selectedDate="{counter.cntOt}"/>
</mx:FormItem>
因为counterAC中放的是Object,二级窗口中自然也用一个Object接一级窗口dataGrid的选定项:
[Bindable]
public var counter:Object;
在二级窗口点击提交按钮的方法中,集中做反向的绑定工作:使用BindingUtils动态的将页面输入域的值绑定回counter:
if(null != counter) { //修改
BindingUtils.bindProperty(counter, "cnt", cnt, ["selectedItem","data"]);
BindingUtils.bindProperty(counter, "cntCls", cntCls, ["selectedItem","data"]);
BindingUtils.bindProperty(counter, "cntOt", cntOt, "selectedDate");
BindingUtils.bindProperty(counter, "cntCt", cntCt, "selectedDate");
BindingUtils.bindProperty(counter, "cntPot", cntPot, "selectedDate");
BindingUtils.bindProperty(counter, "cntPct", cntPct, "selectedDate");
PopUpManager.removePopUp(this);
} else { //增加
//add item into counterDg's dataProvider : counterAC
this.dispatchEvent(new Event("addCounter"));
}
因为counter为Object类型,自然这个警告及时出现了:
warning: unable to bind to property 'cntCt' on class 'Object' (class is not an IEventDispatcher)
这时候让我费解的情况发生了:[b][size=medium]尽管有上面的警告,但通过debug跟踪,发现二级页面的输入域的值还是被成功绑定到了一级TitleWindow的counterAC,counterAC的值已经变成了变化后的值;但怪就怪在:[color=red]使用counterAC作为dataProvider的counterDg没有随着二级TitleWindow的关闭而自动刷新!但通过滚动counterDg的滚动条,使更新的数据行在可见区域中不可见,再滚回来后,你会发现counterDg中刚才错误的数据行变成正确的了![/color][/size][/b]
明明警告我说“不能绑定Object的属性xxx”,却还绑定成功了;刚要以为这个警告无关紧要,却发现绑定仅仅对counterAC起了作用,可是却不会刷新使用counterAC作为dataProvider的counterDg,这算什么个事啊。。。
既然有这样的问题存在,那就从警告入手,着手解决。通过将counterAC中放ObjectProxy对象而不是放Object对象,来解决掉这个警告:
//counterAC初始化的改动:
var counter1:Object = new Object();
counter1.xxx = "yyy";
...
counterAC.addItem(new ObjectProxy(counter1)); //由原来的直接放Object,改为放ObjectProxy
//二级页面中接受一级页面dataGrid当前选定行的变量counter也改为ObjectProxy类型:
[Bindable]
public var counter:ObjectProxy;
//一级页面修改函数在为二级页面counter赋值时也赋ObjectProxy:
protected function editFidsDepfCounterHandler(event:MouseEvent):void
{
//DateGrid的selectedItem返回的是Object类型
var selectedItem:Object = counterDg.selectedItem;
if(null == selectedItem) {
Alert.show("请选择要修改的记录!");
} else {
var win : AddFidsDepfCounterWindow = new AddFidsDepfCounterWindow();
win.counter = new ObjectProxy(selectedItem);
win.title="修改";
PopUpManager.addPopUp(win,this,true);
PopUpManager.centerPopUp(win);
}
}
增加时,通过addItem加到一级页面counterAC中的也应该是ObjectProxy:[quote]//二级页面中:
<fx:Declarations>
<!-- <fx:Model> tag is compiled into an ActionScript object of type mx.utils.ObjectProxy -->
<fx:Model id="addCounterInfo">
<counter>
<cnt>{cnt.selectedItem.data}</cnt>
<cntCls>{cntCls.selectedItem.data}</cntCls>
<cntOt>{cntOt.selectedDate}</cntOt>
<cntCt>{cntCt.selectedDate}</cntCt>
<cntPot>{cntPot.selectedDate}</cntPot>
<cntPct>{cntPct.selectedDate}</cntPct>
</counter>
</fx:Model>
</fx:Declarations>
//一级页面中:
protected function addFidsDepfCounterHandler(event:MouseEvent):void
{
var win : AddFidsDepfCounterWindow = new AddFidsDepfCounterWindow();
win.title="增加";
win.addEventListener("addCounter", saveNewCounter);
PopUpManager.addPopUp(win,this,true);
PopUpManager.centerPopUp(win);
}
protected function saveNewCounter(event:Event):void
{
//trace(event);
var win:AddFidsDepfCounterWindow = event.target as AddFidsDepfCounterWindow;
counterAC.addItem(win.addCounterInfo); //因为addCounterInfo是通过<fx:Model>定义的,所以它本省就是个ObjectProxy类型的对象
PopUpManager.removePopUp(win);
}
[/quote]
至此,问题解决,一级页面dataGrid在二级页面点击确定后被成功刷新,也没有了刚才的警告。
明白了一个道理:flex中的warning不比error影响力小!千万不能置之不理!
[color=red][size=medium][b]关于ObjectProxy:
Using Flex 4.5 / Using data-driven UI components / Storing data
-> Defining a data model:
[url]http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7b51.html#WS2db454920e96a9e51e63e3d11c0bf66ba1-7ffb[/url][/b]
[/size][/color][quote]The most common type of MXML-based model is the <fx:Model> tag, [color=red]which is compiled into an ActionScript object of type mx.utils.ObjectProxy[/color], which contains a tree of objects when your data is in a hierarchy, with no type information. The leaves of the Object tree are scalar values. Because models that are defined in <fx:Model> tags contain no type information or business logic, you should use them only for the simplest cases. Define models in ActionScript classes when you need the typed properties or you want to add business logic.[/quote]
[color=red][size=medium][b] -> Using a data model as a value object:
[url]http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf66ba1-7ff7.html[/url][/b]
[/size][/color]
[color=red][size=medium][b]under the hood flex data model using the fx:model and fx:xml tags:
[url]http://elromdesign.com/blog/2009/07/20/under-the-hood-flex-data-model-using-the-fxmodel-and-fxxml-tags/[/url][/b]
[/size][/color]
通过remoteObject调用后台得到的result也可能本身就是ObjectProxy类型的,只要:
[url]http://tech.groups.yahoo.com/group/flexcoders/message/66621[/url][quote]You'll have to determine why an ObjectProxy is being created... typically [b]it's because an anonymous Object was returned and RemoteObject had makeObjectsBindable="true" [/b](which it is by default).[/quote]我的返回结果为ObjectProxy的例子:[quote]java后台,返回类型是Map:
public Map<FidsDevice, List<FidsChannelRefDev>> findDevAndChannelByDevId(String devId) {
return this.iFidsDeviceService.findDevAndChannelByDevId(devId);
}
flex前台,makeObjectsBindable="true":
<mx:RemoteObject id="iFidsDeviceFlexService" destination="iFidsDeviceFlexService" makeObjectsBindable="true">
<mx:method name="findDevAndChannelByDevId" result="devAndChannelDataHandler(event)" >
<mx:arguments>
<id>{updatedDevId}</id>
</mx:arguments>
</mx:method>
</mx:RemoteObject>
[/quote]
使用ObjectProxy时有个注意事项:
[url]http://www.smithfox.com/?e=96[/url][quote]只能处理当前所代理类的直接属性, 不能感知nested field property变化, 这明显和它声明实现IPropertyChangeNotifier接口是不符的.[/quote]