You need to create custom columns for a dataGrid.
Use the DataGridColumn tag to specify custom properties for columns in a DataGrid.
This recipe adds three DataGridColumn tags to the columns property of a DataGrid. It uses a data file titled homesforsale.xml, although the data that you use could have any name and represent any array of information. The DataGridColumn tags specify the order in which to display the properties of the objects in the dataProvider and the titles to use for the column headers. The dataField property of the DataGridColumn specifies the property of the object to be displayed in the cells of that column. In this example, the object's range property is not displayed in the DataGrid control because there is no DataGridColumn with a dataField associated to the range property:
<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/halo"
creationComplete="initApp()">
<fx:Declarations>
<mx:HTTPService id="srv" url="assets/homesforsale.xml" resultFormat="object" result="onResult(event)"/>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
[Bindable]
private var homesForSale:ArrayCollection;
private function initApp():void {
this.srv.send();
}
private function onResult(evt:ResultEvent):void {
this.homesForSale = evt.result.data.region;
}
]]>
</fx:Script>
<mx:DataGrid id="grid"
width="100%"
height="100%"
dataProvider="{homesForSale}">
<mx:columns>
<mx:DataGridColumn headerText="Total No." dataField="total"/>
<mx:DataGridColumn headerText="City" dataField="city"/>
<mx:DataGridColumn headerText="State" dataField="state"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
The DataGridColumn supports further customization of the display through the use of itemRenderers. The following code sample adds a new DataGridColumn that uses a custom renderer, RangeRenderer, to render the range property in a more meaningful way. The range property contains three values that indicate the percentage of houses for sale based on their price ranges (range1 contains the percentage of houses on sale for under $350,000, range2 is the percentage of houses on sale for between $350,000 and $600,000, and range3 contains the houses going for over $600,000):
<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/halo"
creationComplete="initApp()">
<fx:Declarations>
<mx:HTTPService id="srv" url="assets/homesforsale.xml"
resultFormat="object" result="onResult(event)"/>
</fx:Declarations>
<mx:DataGrid id="grid"
width="100%"
height="100%"
dataProvider="{homesForSale}">
<mx:columns>
<mx:DataGridColumn headerText="Total No." dataField="total"/>
<mx:DataGridColumn headerText="City" dataField="city"/>
<mx:DataGridColumn headerText="State" dataField="state"/>
<mx:DataGridColumn headerText="Price Ranges" dataField="range"
itemRenderer="oreilly.cookbook.flex4.RangeRenderer"/>
</mx:columns>
</mx:DataGrid>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
[Bindable]
private var homesForSale:ArrayCollection;
private function initApp():void {
this.srv.send();
}
private function onResult(evt:ResultEvent):void {
this.homesForSale = evt.result.data.region;
}
]]>
</fx:Script>
</s:Application
The RangeRenderer shown in the following code uses the range percentage values to draw color-coded bars that indicate the values of each range. This is done by overriding the updateDisplayList() method to draw the colored bars using the drawing API:
package {
import flash.display.Graphics;
import mx.containers.Canvas;
public class RangeRenderer extends Canvas {
override public function set data(value:Object):void {
super.data = value;
if(value!= null && value.range != null) {
this.invalidateDisplayList();
}
}
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void {
var g:Graphics = this.graphics;
if(this.data) {
var w1:Number = (this.data.range.range1 * unscaledWidth)/100;
var w2:Number = (this.data.range.range2 * unscaledWidth)/100;
var w3:Number = (this.data.range.range3 * unscaledWidth)/100;
var x1:Number = 0;
var x2:Number = w1;
var x3:Number = w1 + w2;
g.beginFill(0x0000ff);
g.drawRect(x1,0,w1,unscaledHeight);
g.beginFill(0x00ff00);
g.drawRect(x2,0,w2,unscaledHeight);
g.beginFill(0xff0000);
g.drawRect(x3,0,w3,unscaledHeight);
}
}
}
}
If you want to take advantage of the Spark ItemRenderer, note that you can also use that within the DataGrid by implementing the IListItemRenderer interface, as shown here:
<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/halo" width="400" height="300"
implements="mx.controls.listClasses.IListItemRenderer">
<fx:Script>
<![CDATA[
import mx.controls.listClasses.IListItemRenderer;
// include layout logic here
]]>
</fx:Script>
<s:states>
<s:State name="normal"/>
<s:State name="disabled"/>
</s:states>
</s:ItemRenderer>
However, be aware that if you use the Spark ItemRenderer, not all of the state functionality may work in the same way as it does in the Spark List.
Related recipe: Specifying sort functions for DataGrid columns.
This recipe was originally contributed by Joshua Noble as part of O'Reilly's Flex 4 Cookbook.
+