开始的代码大概是这个样子的,点击修改按钮的时候,传递该行data对象,给修改窗口。 <fx:Script> <![CDATA[ public function modifyReportTypeItem(data:ReportTypeItem):void { var addReportItemWindow:AddReportTypeItemTitleWindow= new AddReportTypeItemTitleWindow(); addReportItemWindow.currTypeId = this.currTypeId; //报表类型ID addReportItemWindow.pageState = "update"; //更新 addReportItemWindow.updateReportTypeItem = data; //要更新的对象 PopUpManager.addPopUp(addReportItemWindow,this, true); PopUpManager.centerPopUp(addReportItemWindow); } >> </fx:Script> <mx:DataGrid width="100%" height="300" id="dataGrid" creationComplete="dataGrid_creationCompleteHandler(event)" dataProvider="{getReportTypeItemListResult.lastResult}"> <mx:columns> <mx:DataGridColumn headerText="项目名" dataField="itemName" width="120"/> <mx:DataGridColumn headerText="操作" paddingLeft="5" width="200"> <mx:itemRenderer> <fx:Component> <mx:HBox> <fx:Script> <![CDATA[ import valueObjects.ReportTypeItem; >> </fx:Script> <mx:Button label="修改" click="this.outerDocument.modifyReportTypeItem(data as ReportTypeItem)"/> <mx:Button label="删除" click="this.outerDocument.deleteReportTypeItem(data as ReportTypeItem)"/> </mx:HBox> </fx:Component> </mx:itemRenderer> </mx:DataGridColumn> </mx:columns> </mx:DataGrid>
发现,数据>=2条时,一切正常。 数据只有一条时,调用modifyReportTypeItem方法时,data是null。 很奇怪,以为是标签什么的写的不对,一顿乱搜,无结果。
后来一想,可能是as ReportTypeItem转型失败了吧,导致结果是null。 所以,把as ReportTypeItem去掉,modifyReportTypeItem方法的参数直接使用Object, 发现有多条数据时,调用modifyReportTypeItem方法时,data是正确的ReportTypeItem类型, 而一条数据时,data是mx.utils.ObjectProxy类型,原来原因如此。
尝试ReportTypeItem(data)进行转型,报错: TypeError: Error #1034: 强制转换类型失败:无法将 mx.utils::ObjectProxy@32b2c11 转换为.... 一搜索,N多的案例啊~~~
原来根本原因是: 服务端的WebService通过SOAP返回数据后, 如果只有1条记录的话,Flex给封装成了一个mx.utils.ObjectProxy对象, 而多条记录时,封装成了mx.collections.ArrayCollection,里面是一个一个正确类型的对象。
又搜索,如何将ObjectProxy对象转回正确的强类型,终于搜得此文: http://forums.adobe.com/thread/485678
照葫芦画瓢,转换的办法如下: ReportTypeItem是我的强类型,data可能是ObjectProxy对象,可能是ReportTypeItem对象。 记得 import mx.utils.ObjectProxy; import com.adobe.serializers.utility.TypeUtility;
public function modifyReportTypeItem(data:Object):void { var targetObj:ReportTypeItem = null; if(data is ObjectProxy){ var obj:Object = TypeUtility.convertToStrongType(data,ReportTypeItem); targetObj = obj as ReportTypeItem; }else{ targetObj = ReportTypeItem(data); } ...... }
哦了,问题解决了。
照文章所说,如果不能访问TypeUtility.convertToStrongType方法,需要将serializers.swc添加到build路径。 Adobe Flash Builder 4.5 Root Directory\eclipse\plugins\com.adobe.flexbuilder.project_4.5.1.313231\ dcradSwcs\4.5\libs\serializers.swc 不过,我这个直接能用,就没管。 我这个是4.0,路径好像是 E:\Program Files (x86)\Adobe\Adobe Flash Builder 4 Plug-in\eclipse\plugins\com.adobe.flexbuilder.dcrad_4.0.0.272416\dcradSwcs\4.0\libs ============================================================================= 原文转帖过来,备用 ============================================================================ Hi, I am calling a web service with the resultFormat set to e4x. When i get the result, it is in XML format. What I need is to convert this to a custom type Value Object (which is actually a class generated from WSDL). I was not finding a way to do this. So I used a SimpleXMLDecoder to decode it to a generic Object. Now my problem is that all the nested objects inside this generic Object are of type "ObjectProxy". So i cannot convert them to my nested value objects. So now what I finally need is either of the following 2 things: 1. A way to convert the ObjectProxy to my custom type Value Object. Or 2. A way to directly parse the result XML to my Custom type Value Object. Please let me know if I need to provide some more clarification. Please help.. This one is really killing me now.... Thanks in advance!! ------------------------------------------------------------------- I know the original poster for this question probably won't get this, but that's not the intention of this post...I just spent the last 6 hours trying to find the answer to the question: how do I convert an ObjectProxy to my Object? Well here's the answer, for any other googlers that find this post (as it's on the first page of results for 'cast objectproxy to object') Let's say you have a service call that returns a generic Object type. In SOAP, you might see the resulting xml tag as '<AnyType/>'. In flex though, it will pretty much always convert this to an ObjectProxy class. You'll find that getting the object out isn't exactly straightforward, and casting it back to the type you want it to be also isn't either. Here's how you do it, and it's actually REALLY simple once you know what you have to do: First, you have to convert the ObjectProxy to an Object type. To do so, you must use the 'object_proxy' namespace itself. Here's the code to do that import mx.utils.ObjectProxy; import mx.utils.object_proxy; var myObjectProxy:ObjectProxy = new ObjectProxy(myStronglyTypedObject); var obj:Object = myObjectProxy.object_proxy::object; That code right there will take 'myObjectProxy' and pull out the original object into a general Object variable (NOTE: the object reference is read only according to the docs.) That's only half of the battle though, as then you still need to cast your object back. I have read in serveral sources that you can use an 'as MyType' method to convert the object from there, but I could not get that to work. Traditional casting (i.e. MyType(obj)) only resulted in a runtime error as well. These may work for you if you proxied your object from an existing flex object, but they will NOT work if you pulled it from a service call response's ObjectProxy. Either way though, the solution is just as short to type in the case that you pulled it from a service call response: import com.adobe.serializers.utility.TypeUtility; obj = com.adobe.serializers.utility.TypeUtility.convertToStrongType(obj,MyT ype); (if you can't access that method you probably need to add the serializers.swc from the framework to your build path: Adobe Flash Builder 4.5 Root Directory\eclipse\plugins\com.adobe.flexbuilder.project_4.5.1.313231\ dcradSwcs\4.5\libs\serializers.swc This will convert your object to the type you want it to be. AND YOUR DONE. No more searching for the full answer folks, and no more converting your service calls to e4x instead. Now, if you want to know why this works but casting doesn't stick around...if you don't care, don't waste your time reading the rest of this: Why is it that your other service calls can parse the xml data from a SOAP response to any predefined type from the SOAP service, but casting the proxied version to that type does not work? Your service calls are dynamically generated from the SOAP data, so obviously flex doesn't just 'know' how to do that...and your SOAP objects do extend the Object class...so what gives? If you look at the dynamically generated web service code from flex, you will see that each service call is told what the result type should be. Then the entire AbstractOperation (your client-side web service class) is given a convertResultHandler function that grabs the data from the result and converts it to the type defined by the service. You won't get very far just looking at the generated code though, it's far to abstracted. But if you look at the serializers.swc compiled code (you'll have to decompile it) you will get an idea of what it is that that handler function does. That handler function basically takes it and checks if it's an ArrayCollection/Array or an Object and then defers conversion of the object/array to separate functions called 'convertToStrongType' and 'convertListToStrongType'. These functions take in your object, a class to convert it to, and return the passed in conversion class. Bingo. Now, you will see that you can take that object and use the convertToStrongType and convertListToStrongType functions from the serializers swc to perform the conversions you need. The benefit of this is that these functions are the EXACT SAME FUNCTIONS that handle converting your objects from the webservice result, so you can pretty well bet you won't loose any data like you would with single level reflection utilities and such. As a side note of the usefullness of this. If you have a C# back end web service that returns a List of Object type, meaning that you can toss in all kinds of different objects into the same list, then you can use this in conjuction with an object interrogation function to determine the objects type to perform your conversions. I REALLY hope this helps some other folks save themselves from pulling out their hair or wasting entire days trying to figure out the answer before switching to some off the wall setup that'll make your code more complex! ==============================
|