Creating item renderers and item editors for the Spark DataGrid control

You can create custom item renderers and item editors to control the display of the cells of the Spark DataGrid and Grid controls. You can also create custom item renderers for the header cells of each column of the grid.

You set a custom renderer or editor for each column of the grid. Use the GridColumn.itemRenderer, GridColumn.itemEditor, and GridColumn.headerRenderer properties to specify your custom renderer or editor.

You typically create custom item renderers and item editors in MXML. However, for the highest performance, create them in ActionScript.

The IGridItemRenderer and IGridItemEditor interfaces

Item and header renderers must implement the IGridItemRenderer interface. Item editors must implement the IGridItemEditor interface. The following table describes these interfaces:

Interface

Implemented by

Notes

IGridItemRenderer

Custom item and header renderers

All custom item and header renderers must implement the IGridItemRenderer interface. The base interface of IGridItemRenderer is IDataRenderer, the interface implemented by item renderers for the Spark list-based controls.

IGridItemEditor

Custom item editors

All custom item editors must implement the IGridItemEditor interface. The base interface of IGridItemEditor is IDataRenderer.

Using the predefined item renderers

When using the DataGrid control, you want to ensure the highest performance possible. One of the main factors affecting performance is the time required to render of each visible cell of the grid. Therefore, you want your item renderers to perform at the highest level.

Flex defines several item renderers that you can use to achieve high performance with the DataGrid control. By default, the DataGrid control uses the DefaultGridItemRenderer renderer. This renderer is written in ActionScript to provide good performance across all platforms.

The following table describes the item renderer classes that ship with Flex:

Item Renderer

Use

spark.skins.spark.DefaultGridItemRenderer

The default item renderer that displays the cell data in a text label using the UIFTETextField control. This class is not intended to be extended. Create a custom item renderer based on the GridItemRenderer class.

Because it supports the Flash Text Engine (FTE), this item render also supports bidirectional text.

spark.skins.spark.UITextFieldGridItemRenderer

Optimized for deployment on Microsoft Windows. For Windows, it provides improved performance over the DefaultGridItemRenderer. For other operating systems, use DefaultGridItemRenderer for best performance.

Because it is based on the TextField component, this item renderer does not support bidirectional text.

spark.components.gridClasses.GridItemRenderer

The base class for custom item renderers. This class implements the IGridItemRenderer interface.

Creating an item renderer for a Spark DataGrid

Item renderers for the Spark list-based controls, such as List, must implement the IDataRenderer interface. Item renderers for the Spark DataGrid must implement the IGridItemRenderer interface, which is derived from the IDataRenderer interface. Therefore, the process of creating an item renderer for the DataGrid is similar to creating one for the List control.

An item renderer is associated with a column of the DataGrid control. The item renderer then controls the appearance of each cell in the column. However, each item renderer has access to the data item for an entire row of the DataGrid control. Use the data property of the item renderer to access the data item.

By accessing the data item for the entire row, the item renderer can display multiple data fields, or display a single value created from multiple fields. For example, each row of the data provider for the DataGrid control in the following example contains four fields:

<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkDGComplexIR.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="450" height="450">
    
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            
            // Data includes URL to album cover.
            [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> 
    
    <s:DataGrid id="myGrid" 
        dataProvider="{initDG}"
        variableRowHeight="true">   
        <s:columns>
            <s:ArrayList>
                <s:GridColumn dataField="Artist"/>
                <s:GridColumn dataField="Album" itemRenderer="myComponents.DGComplexIR"/>
                <s:GridColumn dataField="Price"/>
            </s:ArrayList>
        </s:columns>       
    </s:DataGrid>      
</s:Application>

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

However, the DataGrid control only defines three columns. It then uses the DGComplexIR.mxml item renderer to display the Album and Cover fields in a single column. The item render is shown below:
<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\myComponents\DGComplexIR.mxml -->
<s:GridItemRenderer 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:VGroup height="100" paddingTop="10">
        <s:Label id="albumName" 
            width="100%" 
            text="{data.Album}"/>
        <s:Image id="albumImage" 
            source="{data.Cover}"/>    
    </s:VGroup>
</s:GridItemRenderer>

Notice how the item renderer uses the data property of the item renderer to access the data item that corresponds to the entire row of the DataGrid control.

Creating inline renderers

In the previous example, the item renderer was defined in a file separate from the main application file. You can define inline item renderers for the DataGrid control. By using an inline item renderer, your code can all be defined in a single file. To define an inline item renderer, you use the <fx:Component> tag. For example using inline item renderers, see Defining an inline item renderer for a Spark container.

The following example creates an inline item renderer by using the Spark Label control:

<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkDGStyledIR.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="450" height="450">
    
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            
            // Data includes URL to album cover.
            [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>
    
    <s:DataGrid id="myGrid" 
        dataProvider="{initDG}"
        variableRowHeight="true">   
        <s:columns>
            <s:ArrayList>
                <s:GridColumn dataField="Artist">
                    <s:itemRenderer>
                        <fx:Component>
                            <s:GridItemRenderer>
                                <s:Label id="labelDisplay" fontSize="24"/>
                            </s:GridItemRenderer>
                        </fx:Component>
                    </s:itemRenderer>    
                </s:GridColumn>
                <s:GridColumn dataField="Album"/>
                <s:GridColumn dataField="Price"/>
            </s:ArrayList>
        </s:columns>       
    </s:DataGrid>
</s:Application>

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

Creating a header renderer for a Spark DataGrid

The DataGridSkin class uses the GridColumnHeaderGroup component to control the display of the column headers. The GridColumnHeaderGroup component displays a row of headers cells, where the vertical edges of the header cells are aligned with the grid columns.

The GridColumnHeaderGroup component arranges header renderer instances in a row, where the left and right edge of each renderer match the corresponding column. The renderers' height is the maximum preferred height for all of the displayed header renderers.

Like the Grid control and item renderers, the GridColumnHeaderGroup class only creates as many column header renderers and separators as are visible. Renderers and separators that have been scrolled out of view are recycled.

By default, the GridColumnHeaderGroup component uses the spark.skins.spark.DefaultGridHeaderRenderer class as the header renderer. To create a custom header renderer, define the renderer in MXML or ActionScript. Header renderers must implement the IGridItemRenderer interface.

Then, use the Grid.headerRenderer property to specify to use the custom renderer for the column.

Creating an item editor for a Spark DataGrid

The DataGrid control includes an editable property that you set to true to let users edit grid cells. By default, the value of the editable property is false, which means that you cannot edit the cells.

For a DataGrid control, setting the editable property to true enables editing for all columns of the grid. You can disable editing for any column by setting the GridColumn.editable property to false.

Item editing is cell based. To edit a cell, first select the cell or cell row, depending on the selection mode of the grid. Then select the cell to edit. If editing is enabled, an item editor appears over the selected cell.

Note: While an item editor is associated with a single cell, the editor actually has access to the data provider element for the entire row of the selected cell. Therefore, the item editor can access and modify any data for the row.

All item editors must implement the IGridItemEditor interface. The GridItemEditor class implements the IGridItemEditor interface. GridItemEditor also adds the value property that you can use to pass data to and from the item editor. Most custom item editors are created as subclasses of GridItemEditor.

The two most important questions when dealing with an item editor are:

  • How do you pass data to the item editor?

    Use the bindable GridItemEditor.value property to pass data to the item editor. The data type of the value property is Object, so you can use it to pass a single value to the item editor, or you can use it to pass multiple items as fields of the Object.

    The GridItemEditor class implements the value property as a setter and a getter method. When the item editor is created, Flex calls the setter method, passing the cell data from the data provider item for the row. Typically, you override the setter method in your item editor to initialize any items in the item editor from the cell data. The value property only exists while the item editor is open.

    To access the data provider element for the entire row, use the data property of the item renderer.

  • How do you pass data back to the DataGrid control from the item editor?

    Use the GridItemEditor.value property to pass data back to the control. Typically, in your item editor you override the getter method for the value property to return any results back to the DataGrid control. The DataGrid control writes the returned value to the data field of the data provider element for the row that corresponds to the edited cell.

    The item editor uses the IGridItemEditor.save() method to write the value property to the data provider of the DataGrid control. You can override the save() method to control how the value property is written to the data provider. For example, the item editor might return multiple values that you want to write to multiple fields of the data provider element for the row. Override the save() method in this situation to update the data provider.

Using the predefined item editors

Flex ships with two item editors that you can use in your application. The following table describes these item editor classes:

Item Editor

Use

spark.components.gridClasses.DefaultGridItemEditor

Uses a Spark TextArea control to let you edit the text value of a cell.

By default, the DataGrid control uses the DefaultGridItemEditor class.

spark.components.gridClasses.ComboBoxGridItemEditor

Uses a Spark ComboBox control to display a drop-down list of cell values. Select a value to set the new value of the cell.

The following example shows a DataGrid control that uses the ComboBoxGridItemEditor class as the item editor:
<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkDGComboBoxIE.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="450">
    <fx:Script>
        <![CDATA[                
            import mx.collections.ArrayCollection;
            
            [Bindable]
            private var myDP:ArrayCollection = new ArrayCollection([
                {label1:"Order #2314", quant:3, color:'red'},
                {label1:"Order #2315", quant:3, color:'red'}     
            ]);       
        ]]>
    </fx:Script>
    
    <s:DataGrid id="myDG" width="100%" 
                dataProvider="{myDP}" 
                variableRowHeight="true" 
                editable="true" >
        <s:columns>
            <s:ArrayList>
                <s:GridColumn dataField="label1" headerText="Order #"/>
                <s:GridColumn dataField="quant" headerText="Qty"/>
                <s:GridColumn dataField="color" headerText="Color">
                    <s:itemEditor> 
                        <fx:Component> 
                            <s:ComboBoxGridItemEditor> 
                                <s:dataProvider>
                                    <s:ArrayList>
                                        <fx:String>red</fx:String>
                                        <fx:String>green</fx:String>
                                        <fx:String>blue</fx:String>
                                    </s:ArrayList>
                                </s:dataProvider>
                            </s:ComboBoxGridItemEditor> 
                        </fx:Component> 
                    </s:itemEditor>    
                </s:GridColumn> 
            </s:ArrayList> 
        </s:columns >
    </s:DataGrid> 
</s:Application>

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

The item editing process

The following steps describe the lifecycle of an item editor:

  1. An editing session begins in response to a user gesture, such as the user clicking a selected cell. You can also make an explicit call to the DataGrid.startItemEditorSession() method to start the editing session.

  2. Before the item editor appears, the DataGrid dispatches the gridItemEditorSessionStarting event.

    You can cancel the editing session by calling the preventDefault() method in the event handler for the gridItemEditorSessionStarting event.

  3. Flex sets the rowIndex, column, and data properties of the item editor. The data property contains the data provider item for the entire row.

    Flex sets the value property of the item editor to the value of the field in the data provider element that corresponds to the cell being edited.

  4. Flex calls the IGridItemEditor.prepare() method.

    When the prepare() method is called, the editor's size and location have been set and the editor's layout has been validated. You can override the prepare() method to make any final modifications to the editor, such as modifying its visual characteristics or attaching event handlers.

  5. Flex makes the editor visible by setting its visible property to true.

  6. The DataGrid dispatches the gridItemEditorStart event.

  7. When the item editor is first displayed, it is given keyboard focus and its setFocus() method is called. You typically override the setFocus() method of the item editor to shift the focus to a specific component in the item editor.

  8. The user interacts with the editor.

  9. The edit session ends when the user presses the Enter key to save the data, or the Escape key to cancel the edit. The session also ends, and the data is saved, when the users clicks outside the editor, or the editor loses keyboard focus.

    If the editing session is saved, Flex calls the IGridtemEditor.saved() method to write the value property back to the data provider.

    You can end the editing sessions programmatically by calling the DataGrid.endEditorSession() method.

  10. Flex calls the IGridtemEditor.discard() method.

    Override the discard() method to reverse any settings you made in the prepare() method, such as removing event handles, or perform any other cleanup.

  11. The DataGrid dispatches either the gridItemEditorSessionSave or gridItemEditorSessionCancel event.

Example custom item editor

The following example shows a DataGrid control that uses and item editor to let the user change the value of the quant field of the data provider. The second column of the control specifies to use the DGNumStepperEditor.mxml item editor:
<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkDGItemEditor.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="450">
    <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>
    
    <s:DataGrid id="myDG" width="100%" 
        dataProvider="{myDP}" 
        variableRowHeight="true" 
        editable="true" >
        <s:columns>
            <s:ArrayList>
                <s:GridColumn dataField="label1" headerText="Order #"/>
                <s:GridColumn dataField="quant" 
                    headerText="Qty"
                    itemEditor="myComponents.DGNumStepperEditor"/>
            </s:ArrayList> 
        </s:columns >
    </s:DataGrid> 
</s:Application>

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

The DGNumStepperEditor.mxml item editor defines a NumericStepper control to set an integer value. The item editor overrides the setter method for the value property to initialize the NumericStepper control with the current value of the cell.

The override of the getter method for the value property returns the current value of the NumericStepper control. The save() method updates the data provider element for the row of the grid with this value. The DGNumStepperEditor.mxml item editor is shown below:
<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\myComponents\DGNumStepperEditor.mxml -->
<s:GridItemEditor 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 the setter to initialize the NumericStepper control
            // with the cell data.
            override public function set value(newValue:Object):void {
                ns.value = newValue as Number;
            }

            // Override the getter to return the current value of 
            // the NumericStepper control.
            // The save() method updates the data provider element for the
            // row of the grid with this value. 
            override public function get value():Object {
                return ns.value;
            }
            
            // Override setFocus() to shift focus to the NumericStepper.
            override public function setFocus():void {
                ns.setFocus();
            }
        ]]>
    </fx:Script>

    <s:NumericStepper id="ns" width="100%"
        fontWeight="bold"/>
</s:GridItemEditor>

Keyboard and mouse shortcuts with item editors for the Spark DataGrid

The following table describes how the item editor responds to user interaction:

User interaction

Response

F2

If cell selection mode is enabled, edit the cell indicated by the caret.

If row selection mode is enabled, and a cell has not been edited before, edit the first visible cell in the row indicated by the caret. Otherwise edit the cell in the last edited column in the caret row.

Enter

Save the editor's value and close the editor.

Esc

Cancel the editing session by closing the editor without saving the value.

Tab

Save the editor's value, close the editor, and open the editor in the next column that is editable.

Shift+Tab

Save the editor's value, close the editor, and open the editor in the first previous column that is editable.

Ctrl+.

Cancel the editing session by closing the editor without saving the value.

Ctrl+Enter

Save the editor's value, close the editor, and move selection to the same column in the next row.

Ctrl+Shift+Enter

Save the editor's value, close the editor, and move selection to the same column in the previous row.

Single mouse click

Open the editor in response to a single click on the selected cell. The cell must already be selected.

If the Shift or Ctrl key is pressed when the click occurs, then the editor does not open because the Shift and Ctrl keys are used to modify the selection.