In an MX DataGrid control, an item renderer or editor is used in a specific column, so the itemRenderer and itemEditor properties are implemented in the DataGridColumn architec-component
Trang 1A DataGridColumn with custom label formatting
Using a dynamic data field
As I described previously, the custom formatting function for a DataGridColumn requires an argument that references the DataGridColumn that is calling the function The purpose of this argument is to enable you to determine the data field of the current data item dynamically
For example, if the data provider’s data items have phone values in two different properties and you want to format them both with the same logic, you can identify the property you want to for-mat with the array-style expression item[column.dataField] The dataField property of the DataGridColumn returns the name of the property currently being processed, so you need only one custom function to format as many data properties as needed:
private function getPhoneLabel(item:Object, column:DataGridColumn):String
{ var dataValue:String = item[column.dataField];
var pattern:RegExp = /-/g;
var phoneValue:String = dataValue.replace(pattern, “”);
return formatter.format(phoneValue);
}
Trang 2Debugging a custom formatting function
It can be instructive to add a trace() statement to the body of a custom formatting function As you scroll up and down in a DataGrid, the trace statement in the custom function is executed each time the data grid column has to be formatted:
private function getPhoneLabel(item:Object, column:DataGridColumn):String
{ var dataValue:String = item[column.dataField];
var pattern:RegExp = /-/g;
var phoneValue:String = item.phone.replace(pattern, “”);
trace(“original value: “ + dataValue + “, “ + “formatted value: “ + formatter.format(phoneValue));
return formatter.format(phoneValue);
}
Figure 20.8 shows the resulting output in Flash Builder’s Console view when the application is run
in debug mode The Console view displays the trace statements continuously as you scroll up and down in the DataGrid
As a result, you can populate the DataGrid and other list controls with significant amounts of data without causing Flash Player to bog down or overload its memory usage When you run the application described pre- viously with trace statements, try scrolling up and down You’ll notice that the function is called frequently as you scroll, and the existing visual objects are updated with new data n
Advanced Item Renderers and Editors
As described in Chapter 18, all list controls support the custom item renderer and editor tures In an MX DataGrid control, an item renderer or editor is used in a specific column, so the itemRenderer and itemEditor properties are implemented in the DataGridColumn
architec-component
Trang 3Just as with the List control, item renderer and editor components for the DataGridColumn
can be declared in three ways:
l Drop-in renderers These are visual components that you assign to a list control without
any changes to the renderer component’s default property or style settings
l Inline renderers These are components you define and nest within an MXML declaration
of the list control
l Component renderers These are separate visual components that you define as MXML
components or ActionScript classes and assign to the list control’s itemRenderer erty in an MXML declaration You also can assign a component renderer at runtime with ActionScript code by using the mx.core.ClassFactory class (described next)
prop-Cross-Reference
For more information on the three types of item renderer declarations, see Chapter 19 n
At runtime, the DataGridColumn creates an instance of the component and passes its data vider’s current data item as the renderer object’s data property Within the custom component, whether declared inline or as a separate component, you use the data object’s properties with either ActionScript statements or binding expressions to populate visual objects and create your custom presentation
pro-Using the dataChange event
In the following example, a DataGrid component displays contact information from the
contacts.xml file In the first column of the DataGrid, the contact’s first and last names are displayed as a single concatenated string This task can be easily handled with a custom label formatting function:
private function getNameLabel(item:Object, column:DataGridColumn):String
{ return item.firstname + “ “ + item.lastname;
}
In the second column, the DataGrid will display the contact’s full address, formatted as a single
Text control using HTML markup for bold and other formatting To handle this requirement, you can use the dataChange event to update a custom component’s display at runtime This event is dispatched within the custom component whenever the value of its data property is updated You can respond to the event by explicitly updating the custom component’s nested objects as needed
The custom component in Listing 20.9 is extended from the MX Text component When the component’s dataChange event is dispatched, it responds by updating its own htmlText prop-erty with the data object’s new property values
Trang 4</fx:Script>
</mx:Text>
On the Web
The code in Listing 20.9 is available in the Web site files as AddressRenderer.mxml in the chapter20
project’s renderers package n
The application in Listing 20.10 uses the custom component as an item renderer to display plete formatted address information in the DataGrid control’s second column Notice that the
com-DataGrid control’s selectable property is set to false This makes it easier for the user to select the custom component’s text value for copying Also, its variableRowHeight property is set to true to enable the DataGrid columns to adjust their height as needed
return item.firstname + “ “ + item.lastname;
Trang 5} ]]>
</fx:Script>
<fx:Declarations>
<fx:Model id=”contactData” source=”data/contacts.xml”/>
<s:ArrayList id=”contactAC” source=”{contactData.row}”/>
</fx:Declarations>
<mx:DataGrid id=”contactGrid” dataProvider=”{contactAC}”
selectable=”false” variableRowHeight=”true” rowCount=”5”>
FIGURE 20.9
A custom item renderer using the dataChange event
Trang 6Using Spark item renderers
MXAdvancedDataGridItemRenderer These Spark-based components are designed to be used as the root elements for custom item renderers used by the MX DataGrid and
AdvancedDataGrid controls They enable you to use vector graphics and advanced text ing, even though the containing component is an MX-based control
render-You can create a new item renderer for a DataGrid by following these steps:
1 In the Package Explorer view, right-click on the package in which you want to
cre-ate a new renderer component.
2 Choose New ➪ MXML Item Renderer.
3 Select the template Item Renderer for MX DataGrid.
4 Click Finish to create the new item renderer component
Listing 20.11 shows a completed Spark item renderer for a DataGridColumn that incorporates a radial gradient background defined with an FXG graphic and Spark-based Label controls to dis-play the text
<s:Label text=”{data.city}, {data.state}”/>
<s:Label fontWeight=”bold” text=”{data.phone}”/>
</s:VGroup>
</s:MXDataGridItemRenderer>
Trang 7A DataGrid with a Spark-based item renderer with FXG graphics
Using item editors
Like an item renderer, an item editor is a custom component that you display instead of the default label in a DataGridColumn cell An item editor, however, is always an interactive control that enables the user to make changes to the data it represents As with item renderers, you can declare
an item editor using a drop-in, inline, and component syntax
Before you can use an item editor, the DataGrid must have its editable property set to true When you do this, the DataGrid automatically displays an item editor in any cell the user clicks
The default item editor is the TextInput control, so when the user clicks into an editable cell, he’s presented with a TextInput that enables him to change the data When he clicks or tabs out of the cell, the new data is saved to the DataGrid component’s data provider in application memory
When you set the DataGrid component’s editable property to true, all its columns are matically editable Each DataGridComponent has an editable property as well; you stop edit-ing of any particular column by setting its editable property to false
Trang 8auto-In the following code, the DataGrid is editable, but editing is prevented in the firstname and
lastname columns As a result, only the data in the phone column can be changed by the user:
<mx:DataGrid id=”contactGrid” dataProvider=”{contactAC}”
If you apply a labelFunction to a column that’s also editable and uses the default item editor, the user will
be editing the value returned from the labelFunction and not the column’s original data n
Using drop-in item editors
To use a component as a drop-in item editor for an MX DataGrid control, it must implement the
IDropInListItemRenderer interface, and it must be interactive, enabling the user to make changes to data Only a small number of components in the Flex SDK qualify on both counts; they include:
To declare a drop-in editor in a DataGridColumn, you assign the component to the
DataGridColumn component’s itemEditor (if you want to see the component appear only when the user clicks a cell to edit it), or to its itemRenderer (if you want to see it appear on all rows) In either case, you assign the component by its fully qualified class name, including the package prefix:
Trang 9Using the itemEditor and editorDataField properties
When you declare an itemEditor for a DataGridColumn, you also have to set the
DataGridColumn control’s editorDataField property to indicate which field of the item tor component contains the value entered by the user At runtime, the changed value is transferred back to the current data object’s property (the property that’s named as the DataGridColumn
edi-component’s dataField)
For example, if you use a CheckBox control as an item editor, the editorDataField property should be set to selected For a TextInput control, editorDataField should be set to
text (the default), for a NumericStepper, it should be value, and so on
When you set the itemEditor property to a named component, that component is instantiated only when the user clicks into the cell For example, the following code indicates that a CheckBox
control should appear only when the user clicks:
<mx:DataGridColumn dataField=”selected”
itemEditor=”mx.controls.CheckBox”
editorDataField=”selected”
headerText=”” width=”50”/>
Unless the user has clicked a cell that’s editable, the column’s actual value is displayed as a label
When the user clicks in a cell, it displays the CheckBox control
Using the rendererIsEditor property
If you want the item editor component to be displayed in every row of the DataGrid, follow these steps:
1 Assign the editor component DataGridColumn component’s itemRenderer
property instead of itemEditor.
2 Set the DataGridColumn component’s rendererIsEditor property to true.
The following code causes the CheckBox control to appear in every row, regardless of whether the user has clicked into the cell:
The application in Listing 20.12 uses an itemRenderer in its first DataGrid that’s set with
rendererIsEditor to true The renderer is a drop-in component based on mx.controls
CheckBox At application startup, the initApp() method loops through the ArrayList being used as the DataGrid component’s data provider and adds a selected property to each object
That property is then both displayed and edited through the CheckBox that appears on every row
When the user clicks Show Selected, the application loops through the first data provider and locates all data items with selected set to true and adds them to a second ArrayList that’s dis-played in a separate DataGrid
Trang 10protected var selectedData:ArrayList = new ArrayList();
protected function app_creationCompleteHandler(event:FlexEvent):void {
//Add a selected property to each data object on startup for (var i:int=0;i < collection.length; i++)
{ var contact:Object = collection.getItemAt(i);
contact.selected=false;
} } protected function button1_clickHandler(event:MouseEvent):void {
selectedData = new ArrayList();
for (var i:Number=0; i<collection.length; i++) {
if (collection.getItemAt(i).selected) {
selectedData.addItem(collection.getItemAt(i));
} } } ]]>
</fx:Script>
<fx:Declarations>
<fx:Model id=”contactData” source=”data/contacts.xml”/>
<s:ArrayList id=”collection” source=”{contactData.row}”/>
</fx:Declarations>
Trang 11<s:HGroup>
<s:Panel title=”Available Data”>
<mx:DataGrid id=”contactGrid” dataProvider=”{collection}”
<s:Panel title=”Selected Data”>
<mx:DataGrid id=”selectedGrid” dataProvider=”{selectedData}”>
<mx:columns>
<mx:DataGridColumn dataField=”firstname” headerText=”First Name”/>
<mx:DataGridColumn dataField=”lastname” headerText=”Last Name”/>
Tip
When you allow the user to edit data through an editable DataGrid, changes are made to the data collection that’s stored in client memory If you want to save the data to a persistent data store on the server (or on the client, in the case of an Adobe AIR-based desktop application), you need to write code to transfer the changed data If the persistent data store is on the server, you can accomplish this with the Remote Procedure Call (RPC) components (HTTPService, WebService, or RemoteObject) or with the Data Management Service (if using LiveCycle Data Services) With a desktop-based application, you could use the local SQLite database that’s embedded in Adobe AIR n
Trang 12FIGURE 20.11
A renderer displaying every row with rendererIsEditor set to true
Using inline and component editors
As with custom renderers, you can declare custom item editor components with either inline tax or as separate components The benefits of using this syntax instead of drop-in components are that you’re free to use any combination of visual controls and containers, and you can override the components’ default property and style settings
syn-For example, imagine that you wanted to use the DateField control as an item editor, but you modify its default behavior in some way You might set its editable property to true to enable the user to enter a date directly (without having to pick it from the pop-up calendar control) or restrict its available dates:
<mx:DataGridColumn dataField=”dob” editorDataField=”selectedDate”>
are transformed into instances of the ContactVO class This is critical for this example, because
Trang 13the ContactVO class has a dob property typed as a Date, which makes it compatible with the
DateField control that is then used as the property’s editor in the DataGrid
[Bindable]
private var collection:ArrayCollection;
private function resultHandler(event:ResultEvent):void {
collection = event.result.contacts.row;
for (var i:int=0; i<collection.length; i++) {
var newContact:ContactVO = new ContactVO(collection.getItemAt(i));
collection.setItemAt(newContact, i);
} } private function getDateLabel(
item:ContactVO, column:DataGridColumn):String {
return dateFormatter.format(item.dob);
} ]]>
Trang 14DateField control’s button, the calendar control pops up Because the DateField control’s
editable property is true, the user also can click into the TextInput portion of the
DateField and type a value directly
FIGURE 20.12
An itemEditor declared within inline syntax to enable custom properties and behaviors to be declared
Trang 15Using List Controls with Horizontal and Tile Layout
The MX HorizontalList and TileList controls share nearly all the behaviors and ties of the DataGrid and List controls:
capabili-l Data provided to a HorizontalList or TileList is typically displayed using a tom item renderer, declared either inline or as a separate component
cus-l The change event notifies you that the user has selected a data item
l The selectedItem property returns a reference to the selected data item
l The allowMultipleSelection property enables users to select multiple data items by clicking while holding down Ctrl (or Ô on the Mac) and Shift
l As the user scrolls, existing visual objects are reused and their data is populated with the new data As with the DataGrid control, this creates a smooth scrolling experience while enabling these controls to display large amounts of data without overusing Flash Player memory
Cross-Reference
The new Spark List control’s layout property enables you to lay out the control’s data items horizontally or
in tile format If you prefer to use the new Spark skinning architecture, see the instructions for the Spark List control in Chapter 18 n
The difference between the HorizontalList and TileList controls has to do with their out As implied by their component names, the HorizontalList lays out cells in a single row, whereas the TileList lays out cells in a similar fashion to the Tile container, as a grid of objects
lay-in rows and columns
The TileList and HorizontalList controls are almost always used with custom item ers that determine the presentation of each of the list’s cells As with the other list controls, you declare the item renderer component with drop-in, inline, or component syntax
render-The application in Listing 20.14 uses an MX TileList control and an inline renderer to display the contents of an XML file that refers to image files in the project’s assets folder The renderer component uses properties of each XML <slide> element to present an Image and a Label
wrapped in a VBox container
The TileList is wrapped inside a Panel container When the user clicks in one of the
TileList control’s cells, the detail region is updated through the use of binding expressions
Trang 16<fx:Model id=”slideModel” source=”data/slideshow.xml”/>
<s:ArrayCollection id=”slideAC” source=”{slideModel.slide}”/>
</fx:Declarations>
<s:Panel title=”My Photos” height=”430” width=”525”>
<s:layout>
<s:VerticalLayout paddingLeft=”10” paddingRight=”10”
paddingTop=”10” paddingBottom=”10”/>
</s:layout>
<mx:TileList id=”slideList” dataProvider=”{slideAC}”
Trang 17On the Web
The code in Listing 20.14 is available in the Web site files as MXTileList.mxml in the chapter20 project n
Figure 20.13 shows the resulting application, with graphic images and their captions laid out in a gridlike format
FIGURE 20.13
An MX TileList control displaying an inline item renderer
The HorizontalList control uses the same architecture, enabling the user to scroll sideways through content In the application in Listing 20.15, the change event handler saves the current
selectedItem to a bindable Object When the item is selected, the VBox container at the tom of the application becomes visible due to its use of a binding expression in its enabled property
Trang 18currentImage=event.target.selectedItem;
detailPanel.visible=true;
} ]]>
<fx:Model id=”slideModel” source=”data/slideshow.xml”/>
<s:ArrayCollection id=”slideAC” source=”{slideModel.slide}”/>
paddingTop=”10” paddingBottom=”10”/>
</s:layout>
<mx:HorizontalList id=”slideList” dataProvider=”{slideAC}”
width=”100%” height=”125” rowHeight=”125” columnWidth=”120”
<s:Panel id=”detailPanel” title=”Selected Photo”
width=”372” height=”320” visible=”false”>
<s:layout>
<s:VerticalLayout
Trang 19A HorizontalList control with selected information displayed in a detail region
The Spark version of the List control supports a layout property that can be set to an instance of
HorizontalLayout or TileLayout You use ItemRenderer as the base class of its custom
Trang 20<fx:Model id=”slideModel” source=”data/slideshow.xml”/>
<s:ArrayCollection id=”slideAC” source=”{slideModel.slide}”/>
</fx:Declarations>
<s:Panel title=”My Photos” height=”430” width=”550”>
<s:layout>
<s:VerticalLayout paddingLeft=”10” paddingRight=”10”
Trang 21Using the AdvancedDataGrid Control
The AdvancedDataGrid control is an extended version of the DataGrid control that adds these features:
l Sorting by multiple columns
l Row- and column-based styling
l Displaying hierarchical data with an embedded Tree component
l Dynamic grouping of “flat” data into a hierarchical display
l Grouping of multiple columns under a single heading
l Multicolumn item renderers
Note
The AdvancedDataGrid control is available only as part of the Data Visualization components license This package also includes the Flex charting controls The license is sold on a per-developer basis, so there aren’t any ongoing royalties for using these controls Unlike in the Flex 2 product line, the charting and other Data Visualization components aren’t sold as stand-alone products; they’re available only as part a Flash Builder Premium license n
Hierarchical data display
As with the DataGrid, the AdvancedDataGrid control’s data provider is typically in the form
of an ArrayCollection To use the hierarchical data display feature, the objects in the data set should include at least one “grouping” property that can be used to collect and group data items based on their identical values in that property
You can display data that is already in hierarchical form, such as the data created in this ActionScript code:
var employeeAC:ArrayCollection = new ArrayCollection();
employeeAC.source = [{department:”Shipping”, children: [
{firstname:”Kevin”, lastname:”Mount”}, {firstname:”Robert”, lastname:”Lombardi”}]}, {department:”Marketing”,
Trang 22children: [ {firstname:”Brad”, lastname:”Lang”}, {firstname:”James”, lastname:”Jaeger”}]}
];
Notice that the data is structured as an Array containing multiple Object instances, written in ActionScript shorthand notation Each Object contains a department property designed as the grouping field and an Array named children that contains additional data objects
You pass this type of data to the AdvancedDataGrid by first wrapping it in an instance of the
HierarchicalData class This class has a childrenField property that defines which field
of each object is expected to contain child objects Its default value is children, so the data described in the ActionScript code has the expected structure and field names already
Note
The AdvancedDataGrid component handles XML-based data intuitively Child XML nodes are rendered as nodes of the component’s nested Tree control n
The columns property of the AdvancedDataGrid control should contain instances of the
AdvancedDataGridColumn component Its dataField and headerText properties behave just like the DataGridColumn, and its style enables you to specify the color and font on a per-column basis
The application in Listing 20.17 uses a hierarchical data set and an AdvancedDataGrid to play grouped data
employeeAC.source = [ {department:”Shipping”,
Trang 23children: [{firstname:”Kevin”, lastname:”Mount”}, {firstname:”Robert”, lastname:”Lombardi”}]}, {department:”Marketing”,
children: [{firstname:”Brad”, lastname:”Lang”}, {firstname:”James”, lastname:”Jaeger”}]}
];
} ]]>
Trang 24Grouping flat data
Flat data is typically defined as a conventional ArrayCollection containing rows and columns, such as you might import into a Flex application with a call to a database query You can group this type of data structure in an AdvancedDataGrid control by wrapping it in a
GroupingCollection2 object This object contains one or more nested GroupingField
objects that define which columns or properties you want to group on
In MXML, you prepare the data like this:
<mx:GroupingCollection2 id=”gc” source=”{dataCollection}”>
The GroupingCollection2 is then passed to the AdvancedDataGrid component’s
dataProvider To make the GroupingCollection2 update its view, you must call its
refresh() method In the following code, the refresh() method is called when the grid component’s initialize event is dispatched:
Trang 25<fx:Model id=”empModel” source=”data/employees.xml”/>
<s:ArrayCollection id=”employeeAC” source=”{empModel.row}”/>