I have 2 views.
This is the 1-st view.
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
title="MTA">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import adobe.utils.CustomActions;
import data.MTA_Item;
[Bindable]
public static var actions:ArrayCollection;
public var firstItem:MTA_Item;
public var secondItem:MTA_Item;
public var thirdItem:MTA_Item;
public function initItems():ArrayCollection
{
actions = new ArrayCollection();
firstItem = new MTA_Item(1,"Test","Test note");
secondItem = new MTA_Item(2,"DevCom","My First Notes");
thirdItem = new MTA_Item(3,"Auto" , "BMW");
actions.addItem(firstItem);
actions.addItem(secondItem);
actions.addItem(thirdItem);
return actions;
}
override public function set data(value:Object):void
{
if(actions == null)
initItems();
}
]]>
</fx:Script>
<s:VGroup>
<s:Label text="was" >
</s:Label>
</s:VGroup>
<s:List id="items" left="0" right="0" top="0" bottom="0" dataProvider="{actions}" change="navigator.pushView(FormDetails, items.selectedItem)">
<s:itemRenderer>
<fx:Component>
<s:IconItemRenderer label="ID:{data.ID}Name:{data.Name}" />
</fx:Component>
</s:itemRenderer>
</s:List>
</s:View>
2-nd view.
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import views.FlexMobileTestAppHomeView;
public function list_changeHandler(event:Event):void
{
var name:String = _namechange.text;
var notes:String = _note.text;
navigator.pushView(FlexMobileTestAppHomeView,data);
}
override public function set data(value:Object):void
{
}
]]>
</fx:Script>
<s:navigationContent>
<s:Button label="Back"
click="navigator.popToFirstView()"/>
</s:navigationContent>
<s:actionContent >
<s:Button label="save" click="list_changeHandler(event)" />
</s:actionContent>
<s:HGroup verticalAlign="middle" gap="12">
<s:VGroup>
<s:HGroup>
<s:Label text="Name:" />
<s:TextInput id="_namechange" text="{data.Name}">
</s:TextInput>
</s:HGroup>
<s:HGroup>
<s:Label text="Notes:"/>
<s:TextArea id="_note" text="{data.Notes}" />
</s:HGroup>
</s:VGroup>
</s:HGroup>
</s:View>
I need pass data to 2-nd.Then i must edit "name" , and "notes" and button save must return new data to 1-st view. How i can get "actions" from 1-st view and edit?
There are lots of ways to share data between two components. I wrote this blog post about the Flex facilities for sharing data between two Flex Components; however what I think you will be best suited with something more specific.
I'd look into these options:
Override the createReturnObject method in the second view. More information here. Be sure to read the comments for information about accessing the data in recent Flex versions.
Use a framework that supports Dependency Injection. RobotLegs and Swiz are two options I've used in the past. Basically, create a model object that contains a reference to a selectedItem and inject that into both views. Many would claim that this is the best way.
Store a reference to the selected object in a static variable; so that you can reference it in both views. This is a lot less of a learning curve than number 1.
Since you are already passing a reference to the component in the pushView method; are you sure the reference isn't automatically updated when you go back? Really both views are in essence using the same memory reference to get at the data. You may have to refresh the list for the list to pick up on the changes, though. Or I could be wrong on this one.
Related
In Flex 3, it used to be possible to bind a component property within an itemRenderer via outerDocument. So for instance, if there was a image inside an itemRenderer that was only displayed on a given condition of the parent, something like this would work perfectly:
<mx:itemRenderer>
<mx:Component>
<mx:Label text="{data}"/>
<mx:Image id="img" visible="{outerDocument.ShowImage}" includeInLayout="{outerDocument.ShowImage}"/>
</mx:Component>
</mx:itemRenderer>
where the outer document (not the list, but the mxml the list is in) contained something like
[Bindable]
public function get ShowImage():void
{
return showImage;
}
public function set ShowImage(val:Boolean):void
{
showImage = val;
}
I've tried to do the same thing in Flex 4.5 using Spark item renderers using parentDocument, but it doesn't seem to be aware to the binding. When I do this in Flex 4.5, the itemRenderer doesn't seem to be aware when the parentDocument ShowImage changes.
Has anyone seen this issue and is able to offer a solution?
EDIT: Add Spark Source
As requested here is my spark source:
MyItemRenderer.mxml
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:Label id="myLabel" text="{data}/>
<s:Image src="something.png" visible="{parentDocument.ShowImage}" includeInLayout="{parentDocument.ShowImage}"/>
</s:ItemRenderer>
RendererContainer.mxml
<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
private var showImage:Boolean = false;
[Bindable]
public function set ShowImage(val:Boolean):void
{
showImage = val;
}
public function get ShowImage():Boolean
{
return showImage;
}
]]>
</fx:Script>
<!-- Content Group -->
<s:List id="lstCell" width="100%" height="100%" itemRenderer="MyItemRenderer">
</s:List>
</s:Panel>
Ok so there is a checkbox in a wrapper outside of RendererContainer.mxml that dispatches a custom event that is handled by changing a Bindable Boolean. The change in that var then changes the ShowImage property on my RendererContainer component. I would expect that the binding would then be picked up by MyItemRenderer but it doesnt seem to be working.
So my outer wrapper would access ShowImage like this
<comp:RendererContainer id="myId" ShowImage="{myCheckbox.selected}"/>
I think this should do the trick for you, YourTypeHere would be the class of the containing
object, make sure the ShowImage property is public and bindable.
<mx:itemRenderer>
<mx:Component>
<mx:Script>
<![CDATA[
import YourTypeHere;
]]>
</mx:Script>
<mx:Label text="{data}"/>
<mx:Image id="img"
visible="{YourTypeHere(this.parent.ShowImage)}"
includeInLayout="{YourTypeHere(this.parent.ShowImage)}"/>
</mx:Component>
</mx:itemRenderer>
P.s. please don't name properties with a starting uppercase letter, including getters, consider naming it showImage and your private var to something like _showImage instead :D
Your getter seems to have return type as void. Change that to Boolean
[Bindable]
public function get ShowImage():Boolean
{
return showImage;
}
public function set ShowImage(val:Boolean):void
{
showImage = val;
}
This will help.
<s:Image src="something.png" visible="{RendererContainer(ListSkin(parentDocument).parentDocument).ShowImage}" includeInLayout="{RendererContainer(ListSkin(parentDocument).parentDocument).ShowImage}"/>
Following works perfectly fine:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
private var showImage:Boolean = false;
[Bindable]
public function set ShowImage(val:Boolean):void
{
showImage = val;
}
public function get ShowImage():Boolean
{
return showImage;
}
]]>
</fx:Script>
<s:CheckBox label="Select" change="{ShowImage = !ShowImage}"/>
<!-- Content Group -->
<s:List id="lstCell" width="100%" height="100%" dataProvider="{new ArrayCollection(['A','B'])}">
<s:itemRenderer>
<fx:Component>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="true">
<s:layout>
<s:HorizontalLayout/>
</s:layout>
<s:Label id="myLabel" text="{data}"/>
<s:Button label="something.png" visible="{outerDocument.ShowImage}" includeInLayout="{outerDocument.ShowImage}"/>
</s:ItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:List>
</s:Panel>
</s:WindowedApplication>
I got a question about event dispatching and dispatching in flex.
My goal is to pass an email address captured in one component (Comp1) and be passed to another (Comp2). These two components are navigator content of a viewstack. The custom event dispatched the email correctly from Comp1 but somehow could not reach Comp2. The application (Main) looks like :
<fx:Script>
<![CDATA[
import events.LoginEventComplete;
protected function loginHandler(event:LoginEventComplete):void
{
myViewStack.selectedChild = idViewMain;
}
]]>
</fx:Script>
<s:Panel width="100%" height="100%">
<mx:ViewStack id="myViewStack" selectedIndex="0" width="100%" height="100%">
<views:Comp1 id="idViewLogin" login="loginHandler(event)"/>
<views:Comp2 id="idViewMain"/>
</mx:ViewStack>
</s:Panel>
The Comp1 looks like
<fx:Metadata>
[Event(name="login", type="events.LoginEventComplete")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import events.LoginEventComplete;
protected function bnLogIn_clickHandler(event:MouseEvent):void{
var e:LoginEventComplete = new LoginEventComplete("login");
e.workemail = tiWorkEmail.text;
dispatchEvent(e);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:layout>
<s:VerticalLayout verticalAlign="middle" horizontalAlign="center"/>
</s:layout>
<s:Panel width="400" height="500">
<s:Label text="Email" x="130" y="150"/>
<s:TextInput id="tiWorkEmail" top="140" left="180" right="60"/>
<s:Button
id="bnLogIn"
label="Log In"
top="220" left="180"
click="bnLogIn_clickHandler(event)"/>
</s:Panel>
The Comp2 looks like
<fx:Script>
<![CDATA[
import events.LoginEventComplete;
import valueObjects.Employee;
protected function init():void
{
this.addEventListener(LoginEventComplete.LOGIN, mainHandler);
}
private function mainHandler(event:LoginEventComplete):void{
tiWorkEmail.text = event.workemail;
}
]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>
<s:layout>
<s:VerticalLayout verticalAlign="middle" horizontalAlign="center"/>
</s:layout>
<s:Label id="idWorkEmail" text="Email"/>
<s:TextInput id="tiWorkEmail"/>
The custom event LoginEventComplete look like
package events
{
import flash.events.Event;
public class LoginEventComplete extends Event
{
public var workemail:String;
public static const LOGIN:String = "login";
public function LoginEventComplete(type:String)
{
super(type, true, false);
this.workemail = workemail;
}
override public function clone():Event
{
var newEvent:LoginEventComplete = new LoginEventComplete(type);
newEvent.workemail = workemail;
return newEvent;
}
}
}
Can someone help please? Many thanks!
Best David W
You're realizing one of the problems that any hierarchical view structure has to pass information. This problem can be solved in severals ways, but I feel that I should tell you that you might need to look into an application framework if your application is going to get large. One like Parsley or RobotLegs.
Now, onto a solution. You won't be able to use bubbling to go from one sibling component to another, since bubbling goes up the display list (child to parent and so on). You can either listen for the event on the common parent and then push the information into the other sibling, but that's adding a lot of logic on the parent container.
An easy fix would be to create a model (a class that just has public properties to store information) that is bindable on the parent and binded into both siblings. Then if one changes the information, the other can receive that same information (or use bindings).
For example:
<fx:Script>
<![CDATA[
import events.LoginEventComplete;
[Bindable] private var someData:SomeModel = new SomeModel();
protected function loginHandler(event:LoginEventComplete):void
{
myViewStack.selectedChild = idViewMain;
}
]]>
</fx:Script>
<s:Panel width="100%" height="100%">
<mx:ViewStack id="myViewStack" selectedIndex="0" width="100%" height="100%">
<views:Comp1 id="idViewLogin" login="loginHandler(event)" data="{someData}/>
<views:Comp2 id="idViewMain" data="{someData}/>
</mx:ViewStack>
</s:Panel>
I can tell you that dispatched events only move up the hierarchy chain. It sounds like, based on your first code segment, you are trying to get it to move sideways.
<mx:ViewStack id="myViewStack" selectedIndex="0" width="100%" height="100%">
<views:Comp1 id="idViewLogin" login="loginHandler(event)"/>
<views:Comp2 id="idViewMain"/>
</mx:ViewStack>
So, one solution is to have a listener in the main component for the event which then executes a public method in the comp2. It is probably the easiest route.
Another solution may be to store the value in a global object; which both components have references to.
I have one list, which the item render it`s like this:link.
But now I need to enable or disable the button delete depends the view state which my List is inside.
This is my view(which contains the list):
<s:states>
<s:State name="main" /> <!-- Navigation.CART_MAIN -->
<s:State name="cash" /> <!-- Navigation.CART_CASH -->
<s:State name="credit" /> <!-- Navigation.CART_CREDIT -->
</s:states>
<s:List id="theList"
width="480" height="240"
x="69" y="82"
dataProvider="{model.products}"
useVirtualLayout="false"
itemRenderer="com.png.vm.ui.components.ProductCartThumbnail" >
</s:List>
The thing is that I just want to enable the delete buttons inside the itemRender when the screen is using the state "main"
Another option would be to create separate itemRenderers and use the itemRendererFunction.
I've taken this example from similar question that was asked earlier and modified it a bit to suit your needs:
flex 4 list ItemRenderer: how can i have different itemrenderers for different rows?
<fx:Script>
<![CDATA[
import renderers.*;
import mx.core.ClassFactory;
import spark.skins.default.DefaultItemRenderer;
private function list_itemRendererFunc(item:Object):ClassFactory {
var cla:Class = MainItemRenderer;
switch (currentState) {
case "main":
cla = MainItemRenderer;
break;
default:
cla = CashCreditItemRenderer;
break;
}
return new ClassFactory(cla);
}
]]>
</fx:Script>
<s:List id="theList"
x="69" y="82"
itemRendererFunction="list_itemRendererFunc"
dataProvider="{model.products}"
useVirtualLayout="false">
EDIT:
Here's the other solution that was used. You can designate different itemRenderers by declaring different property values for each state.
<s:List id="theList"
width="393" height="223"
x="42" y="69"
dataProvider="{model.products}"
useVirtualLayout="false"
itemRenderer.main="com.png.vm.ui.components.ProductCartThumbnail"
itemRenderer="com.png.vm.ui.components.ProductCartThumbnailReadOnly">
I got exactly the same problem.
I injected the model state (modelState for example) which determines the state of the buttons in the renderer class.
<s:ItemRenderer>
<fx:Script>
<![CDATA[
import spark.components.List;
[Bindable]
public var modelState:String;
public function deleteItem():void {
var parentList:List = owner as List;
// remove the item
parentList.dataProvider.removeItemAt(parentList.dataProvider.getItemIndex(data))
}
]]>
</fx:Script>
<s:HGroup>
<s:Label text="{data}" />
<s:Button id="remove" label="X" click="deleteItem()"
enable="{modelState=='main'}"/>
</s:HGroup>
</s:ItemRenderer>
Yes, I know that this is not the best decision!
I have a class defined like this:
public class Photo
{
public function Photo()
{
}
public var PhotoId:int;
public var Title :String;
public var Subtitle :String;
public var PhotoByteArray:ByteArray ;
public var ThumbnailByteArray:ByteArray;
public var ShowOnlyInFrontpageTop:Boolean;
public var ShowInFrontpageGroup:Boolean;
public var BackgroundColorGradientFrom:String;
public var BackgroundColorGradientTo:String;
public var IsActive :Boolean;
}
I 'm getting diverse objects of this type (Photo) from a WCF service (works fine!). These objects are stored in an ArrayCollection defined like this:
public static var GroupPhotos:ArrayCollection = new ArrayCollection();
I want to show up these photos using a s:List component, like this:
<s:List height="110" id="GroupPhotos" itemRenderer="MyGroupPhotoRenderer">
<s:layout >
<s:HorizontalLayout requestedColumnCount="3" />
</s:layout>
</s:List>
The item renderer is defined this way:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="true"
creationComplete="onItemrenderer_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.FlexEvent;
//when the item has been rendered and is ready to be shown the following method will be called
protected function onItemrenderer_creationCompleteHandler(event:FlexEvent):void
{
img.source = data.ThumbnailByteArray;
}
]]>
</fx:Script>
<s:Group id="PhotoGroup" width="297" height="110" >
<!--<s:Rect id="imgRectangle" alpha="0" width="95" height="65">
<s:stroke>
<s:LinearGradientStroke weight="{GroupBoxBorderWeight}" scaleMode="none"/>
</s:stroke>
</s:Rect>-->
<mx:Image id="img"
width="{PhotoGroup.width}" height="{PhotoGroup.height}"
/>
<s:Label id="title"
fontSize="20"
text="{data.Title}"/>
</s:Group>
</s:ItemRenderer>
The s:Label component shows up correctly whereas the mx:Image component shows up always the same image (don't know if this is the first Image or the last in the array).
What am i missing?
Thanks in advance
Ahhm!!Turns out that this my error! Above i stated that the service is running fine: guess what...it didn't! Fixing the service made the images show up correctly!
Creation complete is only called the first time your renderer is created. Since Flex reuses renderers that means it will only get called the first time. Instead of using creationComplete, override the set data method of your renderer. Unfortunately, s:ItemRenderer doesn't have a set data method, so I'd use a mx:HBox component instead.
Here's a quick example to get you started:
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
override public function set data(value:Object):void
{
super.data = value;
theLabel.text = value["Title"].toString();
theImage.source = data.ThumbnailByteArray;
validateDisplayList();
}
]]>
</fx:Script>
<mx:Label id="theLabel" />
<mx:Image id="theImage" />
</mx:HBox>
I have a Renderer:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Metadata>
[Event(name="addToCart",type="event.ProductEvent")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import events.ProductEvent;
import mx.collections.ArrayCollection;
protected function button1_clickHandler(event:MouseEvent):void
{
var eventObj:ProductEvent=new ProductEvent("addToCart",data.price,data.descript);
dispatchEvent(eventObj);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:states>
<s:State name="normal"/>
<s:State name="hovered"/>
</s:states>
<s:BorderContainer >
<s:layout>
<s:VerticalLayout paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10"/>
</s:layout>
<s:Label text="{data.descript}"/>
<mx:Image source="{data.url}" width="50" height="50" width.hovered="100" height.hovered="100"/>
<s:Label text="{data.price}"/>
<s:Button includeIn="hovered" click="button1_clickHandler(event)" label="buy"/>
</s:BorderContainer>
</s:ItemRenderer>
and the custom event class:
package events
{
import flash.events.Event;
[Bindable]
public class ProductEvent extends Event
{
public var price:String;
public var descript:String;
public function ProductEvent(type:String,price:String, descript:String)
{
super(type);
this.price=price;
this.descript=descript;
}
override public function clone():Event
{
return new ProductEvent(type,price,descript);
}
}
}
but i cannot call that event in a container from the main application
<s:SkinnableDataContainer id="Sk" x="200" y="300" left="100" right="900" dataProvider="{imagesCollection}" itemRenderer="components.ImageRenderer" includeIn="normal" >
<s:layout>
<s:TileLayout/>
</s:layout>
</s:SkinnableDataContainer>
any ideas?
thanks
I want to make this:
<s:SkinnableDataContainer id="Sk" x="200" y="300" left="100" right="900" dataProvider="{imagesCollection}" itemRenderer="components.ImageRenderer" includeIn="normal" ***addToCart=something(event)*** >
Events are not called, so I'm not entirely sure what you want.
You can create an instance of an event class, like this:
var myProductEvent : ProductEvent = new ProductEvent("productEventTypeA", true, ...); // true is for enabling Bubbles, so that the event bubbles up to the listener.
You can dispatch that event from an itemRenderer the same way you would do so if you were using an event elsewhere:
dispatchEvent(myEvent);
Also on the item renderer, declare the event that is going to be dispatched:
[Event(name="productEventTypeA", type="local.events.ProductEvent")]
You can add an event listener on the List or DataGroup component implementing your item renderer so it runs your code after the event is dispatched:
myList.addEventListener("productEventTypeA", onProductEvent); // or a constant instead of "productEventTypeA"
or
myDataGroup.addEventListener("productEventTypeA", onProductEvent); // or a constant instead of "productEventTypeA"
And finally declare your listener function in the same file you added the event listener:
public function onProductEvent(e:ProductEvent):void
{
// do stuff
}
Note: In an itemRenderer, you often want to make your event bubble so that it can be listened to on the component which uses renderers--usually a list based class.
I hope this helps someone, you don't need to do all that...
It's very simple:
ItemRenderer:
protected function dispatchMyCustomEvent():void {
(owner as List).dispatchEvent(new CustomEvent);
}
if the parent isn't a list then just typecast it to what the parent is.
then in your component that has the list you can do the following:
protected function creationComplete():void {
myList.addEventListener(CustomEvent.TYPE, onMyCustomeEvent);
}
protected function onMyCustomEvent(event:MyCustomEvent):void {
// handle the event
}
It's hard to make out what you're trying to do from the question, because of the formatting, and it appears there's some text missing.
However. try making the event bubble, and add the event listener on the list which holds the itemRenderers.
Eg:
<mx:Canvas creationComplete="list1.addEventListener('addToCart',onAddToCart)">
<mx:List id="list1" itemRenderer="com.foo.YourItemRenderer" />
</mx:Canvas>
<!-- YourItemRenderer.mxml -->
<mx:Canvas>
<!-- Other item renderer stuff -->
<mx:Button click="dispatchEvent(new ProductEvent('addToCart'))" />
</mx:Canvas>
// ProductEvent.as
public class ProductEvent {
public function ProductEvent(type:String,bubbles:Boolean=true) {
super(type,bubbles);
// ... etc
}
}
Perhaps this is a little out of scope, but that sort of signaling with events is where MVC frameworks like Cairngorm shine. I usually think of them as AS event buses.
This is possible using the Event metadata tag: http://livedocs.adobe.com/flex/3/html/help.html?content=createevents_3.html
You'll have to sub-class SkinnableDataContainer and add the metadata tag:
[Event(name="addToCart", type="events.ProductEvent")]
public class MySkinnableDataContainer extends spark.components.SkinnableDataContainer
{
}
You can also do it in MXML:
<?xml version="1.0"?>
<!-- ../MySkinnableDataContainer.mxml -->
<s:SkinnableDataContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<mx:Script>
<![CDATA[
import events.ProductEvent;
]]>
</mx:Script>
<mx:Metadata>
[Event(name="addToCart", type="events.ProductEvent")]
</mx:Metadata>
</s:SkinnableDataContainer>
Then use this new class instead of the SkinnableDataContainer:
<MySkinnableDataContainer id="Sk" x="200" y="300" left="100" right="900" dataProvider="{imagesCollection}" itemRenderer="components.ImageRenderer" includeIn="normal" addToCart="something(event)" />
Note: depending on your events bubble property you may have to catch it and then re-forward it along inside of MySkinnableDataContainer.
Make the event bubble:
public function ProductEvent(type:String,price:String, descript:String)
{
super(type, true); // Add bubbles = true instead of default false
this.price=price;
this.descript=descript;
}
Then in your app:
<s:SkinnableDataContainer id="Sk" x="200" y="300" left="100" right="900" dataProvider="{imagesCollection}" itemRenderer="components.ImageRenderer" includeIn="normal" creationComplete="Sk.addEventListener('addToCart', myFunctionToHandle)">
Add an event listener on creation complete.