The DataGrid skin is the container for the DataGrid's Grid and GridColumnHeaderGroup. The default DataGrid skin adds a Scroller, which enables interactive scrolling with scrollbars, a border, and a horizontal separator between the Grid and the GridColumnHeaderGroup.
All of the DataGrid's visual elements, except for the header and item renderers, are optional skin parts. The type of nearly all of the skin parts is IFactory, not because they are "dynamic" skin parts, but just because the corresponding visual elements are created as needed. Nearly all of the DataGrid skin parts are backed by eponymous Grid properties, for example the DataGrid caretIndicator skin part is used to set the grid skin part's caretIndicator property.
The caretIndicator, hoverIndicator, selectionIndicator, columnSeparator, rowSeparator, and headerColumnSeparator skin parts are factories for IVisualElemements. Typically they are specified with GraphicElement classes, for example:
<fx:Declarations>
<fx:Component id="caretIndicator">
<s:Rect>
<s:stroke>
<s:SolidColorStroke color="0x0167FF" weight="1"/>
</s:stroke>
</s:Rect>
</fx:Component>
</fx:Declarations>
The rowBackground skin part defines the visual element that appears behind each row. It's often useful for this element's appearance to depend on the row it's displayed for. Row background elements that implement IGridRowBackground can use the row index or corresponding grid dataProvider item to configure themselves. The initializeRowBackground() method is called before the rowBackground visual element is displayed.
The example below demonstrates how a rowBackground visual element that implements IGridRowBackground can be defined to render alternating row color backgrounds. Note that this common case is already supported in a more general way by the DataGrid alternatingRowColors style, more on that below.
<fx:Declarations>
<fx:Component id="rowBackground">
<s:Rect implements="spark.components.IGridRowBackground">
<s:fill>
<s:SolidColor id="rowBackgroundFillColor" color="0xFFFFFF"/>
</s:fill>
<fx:Script>
<![CDATA[
import spark.components.Grid;
public function initializeRowBackground(grid:Grid, rowIndex:int):void
{
// Even row backgrounds are white, odd rows are green.
rowBackgroundFillColor.color = ((rowIndex & 0x1) == 0x1) ? 0xFFFFFF : 0x338833;
}
]]>
</fx:Script>
</s:Rect>
</fx:Component>
</fx:Declarations>
The alternatingRowColorsBackground skin part is only use when the DataGrid alternatingRowColorStyle is defined. If alternatingRowColorStyle is specified then the alternatingRowColorsBackground skin part is used as the value of the Grid rowBackground property. If both rowBackground skin part was specified, it's overidden.
In the subset of the DataGrid API presented below, all of the public vars are optional (required="false") skin parts and they're all bindable. The SkinPart and Bindable metadata has been elided to make the code easier to read.
package spark.components
{
public class DataGrid extends SkinnableContainerBase implements IFocusManagerComponent
{
/**
* The IVisualElement class used to render the alternatingRowColors style
*/
public var alternatingRowColorsBackground:IFactory;
/**
* The IVisualElement class used to render the grid's caret indicator.
*/
public var caretIndicator:IFactory;
/**
* A reference to the GridColumnHeaderGroup that displays the column headers.
*/
public var columnHeaderGroup:GridColumnHeaderGroup;
/**
* The IVisualElement class used to render the vertical separator between columns.
*/
public var columnSeparator:IFactory;
/**
* The container for the itemEditor visual element.
*/
public var itemEditorLayer:IVisualElementContainer;
/**
* A reference to the Grid that displays the dataProvider.
*/
public var grid:spark.components.Grid;
/**
* The IVisualElement class used to provide hover feedback.
*/
public var hoverIndicator:IFactory;
/**
* The IVisualElement class used to render the background of each row.
*/
public var rowBackground:IFactory;
/**
* The IVisualElement class used to render the horizontal separator between header rows.
*/
public var rowSeparator:IFactory;
/**
* A reference to the Scroller that scrolls the grid.
*/
public var scroller:Scroller;
/**
* The IVisualElement class used to render selected rows or cells.
*/
public var selectionIndicator:IFactory;
//... Remaining Grid API appears elsewhere in this spec
}
}
The current default DataGridSkin follows. Note that one need not copy the entire default skin to create a version that's configured with different visual elements.
In MXML, subclass fx:Declarations override the values of declarations from the super class. So in many cases one can customize the default DataGrid skin by defining a subclass of DataGridSkin and specifying new values of visual elements. For example, to create a version of DataGridSkin that specifies a different visual element as the rowSeparator skin part, one could just write:
<?xml version="1.0" encoding="utf-8"?>
<spark:DataGridSkin
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Declarations>
<fx:Component id="rowSeparator">
<s:Line>
<s:stroke>
<s:LinearGradientStroke rotation="45" weight="5" caps="square">
<s:GradientEntry color="haloBlue" />
<s:GradientEntry color="haloGreen" />
</s:LinearGradientStroke>
</s:stroke>
</s:Line>
</fx:Component>
</fx:Declarations>
</spark:DataGridSkin>
The default DataGrid skin (below) defines a value for all of the skin parts except rowBackground.
<s:SparkSkin
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
alpha.disabled="0.5" minWidth="89" minHeight="84">
<fx:Metadata>
<a href="HostComponent%28%26quot%3Bspark.components.DataGrid%26quot%3B%29">HostComponent("spark.components.DataGrid")</a>
</fx:Metadata>
<s:states>
<s:State name="normal" />
<s:State name="disabled" />
</s:states>
<fx:Declarations>
<fx:Component id="alternatingRowColorsBackground">
<s:Rect implements="spark.components.IGridRowBackground">
<fx:Script>
... code elided for clarity ...
</fx:Script>
<s:fill>
<s:SolidColor id="rowBackgroundFillColor" color="0xFFFFFF"/>
</s:fill>
</s:Rect>
</fx:Component>
<fx:Component id="caretIndicator">
<s:Rect>
<s:stroke>
<s:SolidColorStroke color="0x0167FF" weight="1"/>
</s:stroke>
</s:Rect>
</fx:Component>
<fx:Component id="columnSeparator">
<s:Line>
<s:stroke>
<s:SolidColorStroke color="0xE6E6E6" weight="1" caps="square"/>
</s:stroke>
</s:Line>
</fx:Component>
<fx:Component id="headerColumnSeparator">
<s:Line>
<s:stroke>
<s:SolidColorStroke color="0x696969" weight="1" caps="square"/>
</s:stroke>
</s:Line>
</fx:Component>
<fx:Component id="headerRenderer">
<s:DefaultGridHeaderRenderer>
<s:sortIndicator>
<fx:Component>
<s:Path data="M 3.5 7.0 L 0.0 0.0 L 7.0 0.0 L 3.5 7.0">
<s:fill>
<s:RadialGradient rotation="90" focalPointRatio="1">
<s:GradientEntry id="arrowFill1" color="0" alpha="0.6" />
<s:GradientEntry id="arrowFill2" color="0" alpha="0.8" />
</s:RadialGradient>
</s:fill>
</s:Path>
</fx:Component>
</s:sortIndicator>
</s:DefaultGridHeaderRenderer>
</fx:Component>
<fx:Component id="hoverIndicator">
<s:Rect>
<s:fill>
<s:SolidColor color="0xCEDBEF"/>
</s:fill>
</s:Rect>
</fx:Component>
<fx:Component id="rowSeparator">
<s:Line>
<s:stroke>
<s:SolidColorStroke color="0xE6E6E6" weight="1" caps="square"/>
</s:stroke>
</s:Line>
</fx:Component>
<fx:Component id="selectionIndicator">
<s:Rect>
<s:fill>
<s:SolidColor color="0xA8C6EE"/>
</s:fill>
</s:Rect>
</fx:Component>
<fx:Component id="editorIndicator">
<s:Rect>
<s:fill>
<s:SolidColor color="0xFFFFFF"/>
</s:fill>
</s:Rect>
</fx:Component>
</fx:Declarations>
<!-- fill -->
<!--- Defines the background appearance of the list-based component. -->
<s:Rect id="background" left="1" right="1" top="1" bottom="1" >
<s:fill>
<!--- Defines the color of the background. The default color is 0xFFFFFF. -->
<s:SolidColor id="bgFill" color="0xFFFFFF" />
</s:fill>
</s:Rect>
<!-- column header, separator, scroller with grid -->
<s:VGroup horizontalAlign="justify" gap="0" left="0" right="0" top="0" bottom="0">
<s:GridColumnHeaderGroup id="columnHeaderGroup" paddingLeft="1" paddingTop="1" paddingRight="1"
columnSeparator="{headerColumnSeparator}"
headerRenderer="{headerRenderer}" />
<s:VGroup horizontalAlign="justify" height="100%" gap="-1">
<s:Line id="headerSeparator">
<s:stroke>
<s:SolidColorStroke color="0x696969" weight="1" caps="square"/>
</s:stroke>
</s:Line>
<s:Scroller id="scroller" minViewportInset="1" hasFocusableChildren="false" height="100%">
<s:Grid id="grid" itemRenderer="spark.skins.spark.DefaultGridItemRenderer">
<s:GridLayer s:id="backgroundLayer"/>
<s:GridLayer s:id="selectionLayer"/>
<s:GridLayer s:id="editorIndicatorLayer"/>
<s:GridLayer s:id="rendererLayer" root="{grid}"/>
<s:GridLayer s:id="overlayLayer"/>
</s:Grid>
</s:Scroller>
</s:VGroup>
</s:VGroup>
<!-- border -->
<!--- @private -->
<s:Rect left="0" right="0" top="0" bottom="0" id="border">
<s:stroke>
<!--- @private -->
<s:SolidColorStroke id="borderStroke" weight="1"/>
</s:stroke>
</s:Rect>
<!-- container for the item editor -->
<!--- @private -->
<s:Group id="itemEditorLayer" includeInLayout="false" visible="false"/>
</s:SparkSkin>