Using a Spark item renderer with an MX control

Many MX list-based controls, such as the DataGrid, AdvancedDataGrid, and Tree, support item renderers. These three MX list-based controls also support item editors. Item editors let you create a custom view of data during the editing process. The item editor returns the new data back to the control so that the control can update its data provider.

Flash Builder has built-in support for creating Spark item renderers. To support the use of Flash Builder for creating item editors and item editors for MX controls, Flex defines the mx.controls.listClasses.MXItemRenderer class as a subclass of the Spark spark.components.supportClasses.ItemRenderer class. You can use the MXItemRenderer class to create item renderers and item editors for the MX DataGrid and Tree classes.

Note: Many MX controls, such as the MX List and MX TileList controls, support item renderers or item editors. However, Flex provides the Spark List and Spark TileLayout class as replacements for the MX List and MX TileList controls. Always use the Spark components, when possible, in your application. There is no Spark equivalent for the MX DataGrid, MX AdvancedDataGrid, and MX Tree controls. Therefore, only those MX controls support the MXItemRenderer class.

About MX item renderers and item editors

The MXItemRenderer class simplifies the development of item renderers and editors in Flash Builder. By basing item renderers and item editors on the MXItemRenderer class, your MX controls can take advantage of all of the features of the ItemRenderer class, including Flash Builder support.

All of the functionality of MX item renderers and item editors is supported by the MXItemRenderer class. Therefore, you should be familiar with the architecture of MX item renderers and editors before you create them based on the MXItemRenderer class.

Using the MXItemRenderer class

You base a Spark item renderer or item editor for an MX control on the MXItemRenderer class. While you can base an item renderer or editor on the MXItemRenderer class itself, you typically create them based on one of the following subclasses of MXItemRenderer:

Creating a Spark item renderer for an MX DataGrid control

The following application shows an MX DataGrid control that uses a custom item renderer:
<?xml version="1.0"?>
<!-- itemRenderers\sparkmx\SparkMainDGImageRenderer.mxml -->
<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"
    width="650">
    
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
        
            [Bindable]                
            private var initDG:ArrayCollection = new ArrayCollection([
                {Artist:'Pavement', Album:'Slanted and Enchanted', 
                    Price:11.99, Cover: '../assets/slanted.jpg'},
                {Artist:'Pavement', Album:'Brighten the Corners', 
                    Price:11.99, Cover: '../assets/brighten.jpg'}
            ]);
        ]]>
    </fx:Script>

    <mx:DataGrid id="myGrid" height="400" width="600"
        dataProvider="{initDG}">  
        <mx:columns>
            <mx:DataGridColumn dataField="Artist"/>
            <mx:DataGridColumn dataField="Album"/>
            <mx:DataGridColumn dataField="Cover" 
                itemRenderer="myComponents.RendererDGImage"/>
            <mx:DataGridColumn dataField="Price"/>
        </mx:columns>       
    </mx:DataGrid>  
</s:Application>

The executing SWF file for the previous example is shown below:

In this example, you use the custom item renderer to display the album cover for each album listed in the DataGrid control. The Cover field of the data provider of the DataGrid contains the path to the JPG file for the cover.

Shown below is the definition of the RendererDGImage.mxml file that defines the item renderer:
<?xml version="1.0"?>
<!-- itemRenderers\sparkmx\myComponents\RendererDGImage.mxml -->
<s:MXDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark" 
        xmlns:mx="library://ns.adobe.com/flex/mx">

        <mx:Image id="albumImage" height="175" source="{data.Cover}"/>
</s:MXDataGridItemRenderer>

Notice that this item renderer is based on the MXDataGridItemRenderer class. The item renderer uses the Image control to display the album cover.

The next example also displays the album name and cover image, but uses a single column of the DataGrid to display both fields:
<?xml version="1.0"?>
<!-- itemRenderers\sparkm\SparkMainDGTitleRenderer.mxml -->
<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"
    width="650">
    
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
        
            [Bindable]                
            private var initDG:ArrayCollection = new ArrayCollection([
                {Artist:'Pavement', Album:'Slanted and Enchanted', 
                    Price:11.99, Cover: '../../assets/slanted.jpg'},
                {Artist:'Pavement', Album:'Brighten the Corners', 
                    Price:11.99, Cover: '../../assets/brighten.jpg'}
            ]);
        ]]>
    </fx:Script>

    <mx:DataGrid id="myGrid" width="600"
        dataProvider="{initDG}" 
        variableRowHeight="true">  
        <mx:columns>
            <mx:DataGridColumn dataField="Artist" />
            <mx:DataGridColumn dataField="Album" 
                itemRenderer="myComponents.RendererDGTitleImage" />
            <mx:DataGridColumn dataField="Price"  />
        </mx:columns>       
    </mx:DataGrid>  
</s:Application>

The executing SWF file for the previous example is shown below:

The RendererDGTitleImage.mxml file implements the render. It uses a Spark Label control and the MX Image control to display the album name and cover image in a single cell:
<?xml version="1.0"?>
<!-- itemRenderers\sparkmx\myComponents\RendererDGTitleImage.mxml -->
<s:MXDataGridItemRenderer 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:HorizontalLayout verticalAlign="middle"
            paddingLeft="5" paddingRight="5"/>
    </s:layout>

    <s:Label id="albumName" 
        width="100%" 
        text="{data.Album}"/>
    <mx:Image id="albumImage" 
        source="{data.Cover}"/>    
</s:MXDataGridItemRenderer> 

Creating a Spark item renderer for an MX AdvancedDataGrid control

The following application uses the AdvancedDataGrid control:
<?xml version="1.0"?>
<!-- itemrenderers/sparkmx/SparkHierarchicalADGSimpleRenderer.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Script>
        <![CDATA[
              import mx.collections.ArrayCollection;
                
              include "SimpleHierarchicalData.as";
        ]]>
    </fx:Script>

    <mx:AdvancedDataGrid width="100%" height="100%">
        <mx:dataProvider>
            <mx:HierarchicalData source="{dpHierarchy}"/>
        </mx:dataProvider>
        <mx:columns>
            <mx:AdvancedDataGridColumn dataField="Region"/>
            <mx:AdvancedDataGridColumn dataField="Territory_Rep"
                headerText="Territory Rep"/>
            <mx:AdvancedDataGridColumn dataField="Actual"/>
            <mx:AdvancedDataGridColumn dataField="Estimate"/>
            <mx:AdvancedDataGridColumn id="diffCol" 
                headerText="Difference"/>
        </mx:columns>

        <mx:rendererProviders>
            <mx:AdvancedDataGridRendererProvider column="{diffCol}"
                depth="3" renderer="myComponents.SummaryRenderer"/>
        </mx:rendererProviders>
    </mx:AdvancedDataGrid>
</s:Application>

The executing SWF file for the previous example is shown below:

This application uses the custom item renderer defined in the file SummaryRenderer.mxml to display the value of the Difference column. The value is determined by the difference between the Estimate and Actual columns. If the territory representative exceeded sales estimate, the cell appears in green. If the territory representative did not exceed the estimate, the cell appears in red.

The SummaryRenderer.mxml also includes a CurrencyFormatter to format the value in dollars. The SummaryRenderer.mxml is shown below:
<?xml version="1.0"?>
<!-- itemrenderers/sparkmx/myComponents/SummaryRenderer.mxml -->
<s:MXAdvancedDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    textAlign="center">
    
    <fx:Script>
        <![CDATA[

            override public function set data(value:Object):void
            {
                // Calculate the difference.
                var diff:Number = 
                    Number(value["Actual"]) - Number(value["Estimate"]);
                if (diff < 0)
                {
                    // If Estimate was greater than Actual, 
                    // display results in red.
                    setStyle("color", "red");
                    myLabel.text = "Undersold by " + usdFormatter.format(diff);
                }
                else
                {
                    // If Estimate was less than Actual, 
                    // display results in green.
                    setStyle("color", "green");
                    myLabel.text = "Exceeded estimate by " + usdFormatter.format(diff);
                }
            }
        ]]>
    </fx:Script>

    <fx:Declarations>
        <mx:CurrencyFormatter id="usdFormatter" precision="2" 
            currencySymbol="$" decimalSeparatorFrom="."
            decimalSeparatorTo="." useNegativeSign="true" 
            useThousandsSeparator="true" alignSymbol="left"/>
    </fx:Declarations>

    <s:Label id="myLabel"/>
</s:MXAdvancedDataGridItemRenderer>

Creating a Spark item renderer for an MX Tree control

The following application uses an MX Tree control to display XML data:
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- itemRenderers\tree\SparkMainTreeItemRenderer.mxml -->
<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" 
    initialize="initCollections();">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>

    <fx:Script>
        <![CDATA[
   
            import mx.collections.*;
    
            public var xmlBalanced:XMLList =
                <>
                    <node label="Containers">
                        <node label="DividedBoxClasses">
                            <node label="BoxDivider" data="BoxDivider.as"/>
                        </node>
                        <node label="GridClasses">
                            <node label="GridRow" data="GridRow.as"/>
                            <node label="GridItem" data="GridItem.as"/>
                            <node label="Other File" data="Other.as"/>
                        </node>
                    </node>
                    <node label="Data">
                        <node label="Messages">
                            <node label="DataMessage" 
                                data="DataMessage.as"/>
                            <node label="SequenceMessage" 
                                data="SequenceMessage.as"/>
                        </node>
                        <node label="Events">
                            <node label="ConflictEvents" 
                                data="ConflictEvent.as"/>
                            <node label="CommitFaultEvent" 
                                data="CommitFaultEvent.as"/>
                        </node>
                    </node>
                </>;
                
            [Bindable]
            public var xlcBalanced:XMLListCollection;
    
            private function initCollections():void {
                xlcBalanced = new XMLListCollection(xmlBalanced);
            }
        ]]>
    </fx:Script>

    <mx:Text width="400" 
        text="The nodes with children are in bold red text, with the number of children in parenthesis.)"/>

    <mx:Tree id="compBalanced" 
        width="400" height="500" 
        dataProvider="{xlcBalanced}" 
        labelField="@label"  
        itemRenderer="myComponents.MyTreeItemRenderer"/>
</s:Application>

The executing SWF file for the previous example is shown below:

This application uses the item renderer defined by the MyTreeItemRenderer.mxml file to display the parent nodes in a red, bold font. It also shows the number of child nodes for each parent in parenthesis. Shown below is the definition of MyTreeItemRenderer.mxml:
<?xml version="1.0" encoding="utf-8"?>
<!-- itemRenderers\sparkmx\myComponents\MyTreeItemRenderer.mxml -->
<s:MXTreeItemRenderer 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[

            import mx.controls.treeClasses.*;
            import mx.collections.*;
            
            // Override the set method for the data property
            // to set the font color and style of each node.        
            override public function set data(value:Object):void {
                super.data = value;
                if(treeListData.hasChildren)
                {
                    setStyle("color", 0xff0000);
                    setStyle("fontWeight", 'bold');
                    var tmp:XMLList = 
                        new XMLList(treeListData.item);
                    var myStr:int = tmp[0].children().length();
                    labelDisplay.text =  treeListData.label + 
                        "(" + myStr + ")";
                }
                else
                {
                    setStyle("color", 0x000000);
                    setStyle("fontWeight", 'normal');
                    labelDisplay.text =  treeListData.label;
                }  
            }
        ]]>
    </fx:Script>
    
    <s:HGroup left="0" right="0" verticalCenter="0">
        <s:Rect id="indentationSpacer" 
            width="{treeListData.indent}" height="22" 
            alpha="0">
            <s:fill>
                <s:SolidColor color="0xFFFFFF" />
            </s:fill>
        </s:Rect>
        <s:Group id="disclosureGroup">
            <s:BitmapImage source="{treeListData.disclosureIcon}" 
                width="16" height="16" 
                visible="{treeListData.hasChildren}" />
        </s:Group>
        <s:BitmapImage source="{treeListData.icon}" 
            width="16" height="16"/>
        <s:Label id="labelDisplay" />
    </s:HGroup>
</s:MXTreeItemRenderer>

The item renderer uses the treeListData property of the MXTreeItemRenderer class to determine the information about the tree node. The treeListData property is of type TreeListData. TreeListData defines information such as the depth of the node in the tree, any icon associated with the node, and the data object of the node from the tree’s data provider.

This item renderer overrides the ItemRenderer.data property to control the display of the tree nodes. The override first determines if the node is a parent node and, if so, sets the text display to use a bold, red font. It then adds the number of children to the display of the node.

The second part of the item renderer defines the appearance of the node in the Tree control. In this example, you use a Rect control to define a white background for the node. The item renderer uses two BitmapImage controls to define the appearance of any icons. The Label control defines the appearance of the text displayed by the node.

Creating a Spark item editor for an MX DataGrid control

An MX DataGrid, AdvancedDataGrid, or Tree control displays an item editor when the editable property of the control is set to true. The item editor appears when the user releases the mouse button while over a cell, tabs to the cell, or in another way attempts to edit the cell. By default, the editable property is false.

When creating an item editor for an MX DataGrid or Tree control, the item editor usually returns a single value corresponding to the new value in the control’s data provider. For example, the following item renderer returns a single value named myRetValue:
<?xml version="1.0"?>
<!-- itemRenderers\sparkmx\myComponents\NSEditor.mxml -->
<s:MXDataGridItemRenderer 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[
            public var myRetVal:int = 0;
        ]]>
    </fx:Script>
    
    <!-- Use the valueCommit event when the user selects the 
         cell but does not change the value. -->
    <s:NumericStepper id="myNS"
        value="{data.quant}"
        stepSize="1" 
        maximum="50"
        change="myRetVal=myNS.value;"
        valueCommit="myRetVal=myNS.value;"/>
</s:MXDataGridItemRenderer>

This item editor contains a single NumericStepper control. When the item editor is open, the NumericStepper appears in the DataGrid control. The user can then use the NumericStepper to edit the value of the cell.

The user ends the editing session by removing focus from the cell. Flex then commits the new value in the DataGrid control. The following application uses this item editor:
<?xml version="1.0"?>
<!-- itemRenderers\sparkmx\SparkMainNSEditor.mxml -->
<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">
     
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
        
            [Bindable]
            private var myDP:ArrayCollection = new ArrayCollection([
                {label1:"Order #2314", quant:3, Sent:true},
                {label1:"Order #2315", quant:3, Sent:false}     
            ]);               
        ]]>
    </fx:Script>

    <mx:DataGrid id="myDG" dataProvider="{myDP}" 
            variableRowHeight="true" 
            editable="true" >
        <mx:columns>
            <mx:DataGridColumn dataField="label1" 
                headerText="Order #"/>
            <mx:DataGridColumn dataField="quant" 
                itemEditor="myComponents.NSEditor" 
                editorDataField="myRetVal"/>
        </mx:columns >
    </mx:DataGrid> 
</s:Application>

The executing SWF file for the previous example is shown below:

Notice in the main application that the DataGridColumn uses the itemEditor property to specify the name of the item editor. It uses the editorDataField property to specify the name of the property of the item editor that contains the return value.

Creating an inline Spark item editor for an MX DataGrid control

An MX DataGrid, AdvancedDataGrid, or Tree control can use an inline item renderer or editor. The following example uses a Spark DropDownList control as the item editor for a column of an MX DataGrid control:
<?xml version="1.0"?>
<!-- itemRenderers\sparkmx\SparkDGInlineRenderer.mxml -->
<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"
    width="650">
    
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            
            [Bindable]                
            private var initDG:ArrayCollection = new ArrayCollection([
                {Artist:'Pavement', Album:'Slanted and Enchanted', 
                    Price:11.99, Cover: '../assets/slanted.jpg', Rating:'none'},
                {Artist:'Pavement', Album:'Brighten the Corners', 
                    Price:11.99, Cover: '../assets/brighten.jpg', Rating:'none'}
            ]);
        ]]>
    </fx:Script>

    <mx:DataGrid id="myGrid" height="400" width="600"
        dataProvider="{initDG}" editable="true">  
        <mx:columns>
            <mx:DataGridColumn dataField="Artist"/>
            <mx:DataGridColumn dataField="Album"/>
            <mx:DataGridColumn dataField="Rating" editorDataField="rating">
                <mx:itemEditor>
                    <fx:Component>
                        <s:MXDataGridItemRenderer focusEnabled="true" height="22" >
                            <fx:Script>
                                <![CDATA[
                                    import mx.collections.ArrayList; 
                                    
                                    public function get rating():String {
                                        return  dd.selectedItem;
                                    }
                                ]]>
                            </fx:Script>
                            <s:DropDownList id="dd" top="5" left="5" 
                                selectedItem="{data.Rating}"
                                initialize="dd.dataProvider = 
                                    new ArrayList(['none', 'no good', 'good', 'great'])"/>
                        </s:MXDataGridItemRenderer>
                    </fx:Component>
                </mx:itemEditor>
            </mx:DataGridColumn> 
            <mx:DataGridColumn dataField="Cover" 
                itemRenderer="myComponents.RendererDGImage"/>
            <mx:DataGridColumn dataField="Price"/>
        </mx:columns>       
    </mx:DataGrid>  
</s:Application>

The executing SWF file for the previous example is shown below:

This example adds a Rating column to the DataGrid. The user clicks in a cell of the Rating column to open the item editor. When the user removes focus from the cell, the value of the DropDownList is copied to the data provider of the DataGrid.