Flex Spark List component item order - apache-flex

I have a regular spark list which is sorted correctly when no item renderer is used. However, when the following item renderer is used, the list shuffles and displays items from previous instances of the list. Any help would be appreciated.
<?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="itemRendererInit(event)">
<fx:Script>
<![CDATA[
import flash.utils.setInterval;
import flashx.textLayout.conversion.TextConverter;
import mx.events.FlexEvent;
protected function itemRendererInit(event:FlexEvent):void {
setInterval(resizeItemRenderer, 50);
richtext.textFlow= TextConverter.importToFlow(
'<TextFlow xmlns="http://ns.adobe.com/textLayout/2008"><linkNormalFormat color="#ac0000" textDecoration="none"/><linkHoverFormat color="#ac0000" textDecoration="underline"/><linkActiveFormat color="#ac0000" textDecoration="none"/><p><span fontWeight="bold">' +
data[0].toString() +
':</span><br/><br/>' +
data[1].toString() +
'</p></TextFlow>', TextConverter.TEXT_LAYOUT_FORMAT);
}
private function resizeItemRenderer():void {
richtext.width = parentApplication.width-525;
}
]]>
</fx:Script>
<s:RichEditableText id="richtext"
paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10"
verticalAlign="middle" editable="false" textAlign="left"/>
</s:ItemRenderer>

Just over the top of my head, try overriding commitProperties instead of relying on creationComplete event. On creationComplete, just call invalidateProperties and then call your function from commitProperties().

I eventually found it to be a data binding problem. Thanks #M.D.

Related

How to access MXML component instance in ItemRenderer

I have been developing an Adobe Flex (v3.5 Flex SDK) based application and I have a question on How we can access (call) a method written in MXML file (embeded in script tag) from the ItemRenderer file.
The MXML component has a datagrid and for one of the columns, the itemrenderer is my own custom item renderer.
In my custom item renderer, for some event I need to call a method which exist in its parent MXML component. How do we get access to its parent MXML instance ?
I have explored for this in google and found that we can access to 'data' object which refers to the dataProvider of the datagrid. But I wanted access to the instance of MXML component (so that I can call a method in it) which has the datagrid.
The AdvancedDataGridColumn in AdvancedDataGrid is like this
<mx:AdvancedDataGridColumn dataField="total" headerText="Total" width="120" itemRenderer="renderers.MyItemRenderer"/>
Here MyItemRenderer is a separate action script file.
Appreciate the response.
Thanks
Raagu
As Raghavendra Nilekani suggested This works:
TestGrid.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
[Bindable]
public var data:Array = [
{name:"name",value:"valeu1",timestamp:"423423"},
{name:"name1",value:"valeu2",timestamp:"423423"},
{name:"name2",value:"valeu3",timestamp:"423423"},
{name:"name3",value:"valeu5",timestamp:"423423"}
]
public function calculateValue():Number{
return Math.random();
}
]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>
<mx:VBox height="100%" width="100%">
<mx:AdvancedDataGrid dataProvider="{data}">
<mx:columns>
<mx:AdvancedDataGridColumn itemRenderer="ItemRenderer">
</mx:AdvancedDataGridColumn>
</mx:columns>
</mx:AdvancedDataGrid>
</mx:VBox>
</s:Application>
e ItemRendere.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:MXAdvancedDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
focusEnabled="true"
addedToStage="mxadvanceddatagriditemrenderer1_addedToStageHandler(event)"
>
<fx:Script>
<![CDATA[
[Bindable]
var value:Number;
import mx.containers.VBox;
import mx.controls.AdvancedDataGrid;
protected function mxadvanceddatagriditemrenderer1_addedToStageHandler(event:Event):void
{
var grid:AdvancedDataGrid = ((AdvancedDataGrid)(this.owner));
var box:VBox = ((VBox)(grid.owner))
var comp:TestGrid = (TestGrid)(box.owner);
value = comp.calculateValue();
}
]]>
</fx:Script>
<s:Label id="lblData" top="0" left="0" right="0" bottom="0" text="{value}" />
</s:MXAdvancedDataGridItemRenderer>
Anyway I agree with zenbeni that this lead to a not reausable item renderer.

Flex datagrid header row right click

I got a Datagrid in my Flex application.
I need to make appear a context menu when the header row is right-clicked.
The latter context menu must not appear when the rest of the datagrid items (the ones containing data) are clicked.
Edit: the application runs in AIR environment, so i got no flash-player troubles
In flex, and more generally in flash, there is no way to catch the the right click event.
I'm not sure about the right mouse click, cos flex apps run in flash player, and right click brings up its menu.
The best bet would be to use headerRelease event on your DatagRid. In your event handler you can then create your menu (maybe in a popup or some hovering panel?) and then do what you need to do there.
Read more about it here
edit:
Maybe you could use a contextMenu class, and attach it to your dataGrid.contextMenu?
Below code may help you: -
I have created sample in which i have added only one ITEM. You can convert it and change logic as per requirement. My idea is to provide one of the base logic. You may gey better solution but this can work for you.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<mx:DataGrid id="myDG" width="350">
<mx:dataProvider>
<mx:ArrayCollection>
<mx:source>
<fx:Object Artist="" Price="11.99"
Album="Slanted and Enchanted" />
<fx:Object Artist=""
Album="Brighten the Corners" Price="11.99" />
</mx:source>
</mx:ArrayCollection>
</mx:dataProvider>
<mx:columns>
<mx:DataGridColumn dataField="Artist" headerRenderer="StackLabelRenderer"/>
<mx:DataGridColumn dataField="Album" headerRenderer="StackLabelRenderer"/>
<mx:DataGridColumn id="price" dataField="Price" headerRenderer="StackLabelRenderer"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
StackLabelRenderer.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Label xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
click="dispatchClickEvent()">
<fx:Script>
<![CDATA[
import mx.controls.DataGrid;
import mx.controls.dataGridClasses.DataGridColumn;
import mx.controls.dataGridClasses.DataGridListData;
import mx.core.mx_internal;
private function dispatchClickEvent():void
{
trace("Item Clicked")
}
import mx.controls.Alert;
[Bindable]
private var cm:ContextMenu;
override protected function createChildren():void
{
cm = new ContextMenu();
cm.hideBuiltInItems();
cm.addEventListener(ContextMenuEvent.MENU_SELECT, contextMenu_menuSelect);
this.contextMenu = cm;
}
private function contextMenu_menuSelect(evt:ContextMenuEvent):void {
//condition to check length of column data length
var allNull:Boolean=true;
var columnName:String = DataGridColumn(data).headerText;
for each(var o:Object in DataGrid(owner).dataProvider) {
if(o[columnName] != "") {
allNull=false;
break;
}
}
if(!allNull)
{
var cmi:ContextMenuItem = new ContextMenuItem("First Element...", true);
cmi.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, contextMenuItem_menuItemSelect);
cm.customItems = [cmi];
}
}
private function contextMenuItem_menuItemSelect(evt:ContextMenuEvent):void {
}
]]>
</fx:Script>
</mx:Label>

Adobe Flex 4.5 Spark: Binding ItemRenderer Component to Parent

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>

Navigation within ItemRenderer

How can we navigate within an itemRenderer?
For example, in Views we use the View.navigator (ViewNavigator) to push and pop views, there is no such feature in ItemRenderer.
Navigation within a View (Easy)
<s:View>
<s:HGroup >
<s:Button label="Questionnaire" click="navigator.pushView(view.QuestionnaireCategory1View)"/>
</s:HGroup>
Navigation within a Item Renderer (Impossible?)
<?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"
autoDrawBackground="true" height="56">
<s:HGroup>
<s:Button text="Button" click="?????????"/>
</s:HGroup>
</s:ItemRenderer>
You want to use bubbling events to catch when the user interacts with an item renderer.
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:HGroup>
<s:Button text="Button" click="dispatchEvent(new Event('buttonClicked', true));"/>
</s:HGroup>
</s:ItemRenderer>
Then when do this with whatever is using your item renderer:
<DataGroup id="group" itemRenderer="YourItemRenderer" dataProvider="{someData}" creationComplete="group.addEventListener('buttonClick', someHandlerFunction);" />
And then within your handler function, do whatever action you wanted to do. In this case, I'm adding the event listener on creation complete of the DataGroup, but you can add it to the creation complete event of the main container. This way you keep your item renderer decoupled and reusable, as well as using proper software practices (data in, events out).
In when you create your itemRenderer
<comp:MyItemRenderer navigator="{navigator}"/>
In your itemRenderer (here call MyItemRenderer)
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
autoDrawBackground="true" height="56">
<fx:Script>
<![CDATA[
import spark.components.ViewNavigator;
private var _navigator:ViewNavigator;
public function set navigator(value:ViewNavigator):void
{
_navigator = value;
}
]]>
</fx:Script>
<s:HGroup>
<s:Button label="Button" click="{_navigator.pushView(view.QuestionnaireCategory1View)}"/>
</s:HGroup>

Flex 4 - 9scalling is not working at runtime (although working in Flash)

I created a 9-scalled background in Flash CS5 which is working fine in Flash CS5
But when i imported it as embeded graphic in Flex, and change dimensions in runtime, 9-scalling doesnt work.
Here is my code.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
[Embed(source='mgraphic.swf', symbol='Bck')]
[Bindable]
public var imgCls:Class;
protected function button1_clickHandler(event:MouseEvent):void
{
nineScalled.width = 100 + (this.width - 100) * Math.random();
nineScalled.height = 100 + (this.height - 100) * Math.random();
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout verticalAlign="middle" horizontalAlign="center"/>
</s:layout>
<s:Button label="change" click="button1_clickHandler(event)"/>
<s:BorderContainer id="nineScalled" backgroundImage="{imgCls}" backgroundImageFillMode="scale" width="469" height="187"/>
</s:Application>
Here is the fla file of my 9-scalled file
http://rapidshare.com/files/405441500/9scalledgraphic.fla
Thanks
if you have a sprite/movieclip, that uses 9slice-scaling and you scale this thing directly, it works nicely. If this things is a child of another sprite/movieclip/whatever and you scale that one, the 9slice-scaling of your child does not work anymore.
A workaround for this is normally to write functions, that take size-change requests and then resize the children that use9slice-scaling directly, instead of resizing themselves.

Resources