Monday, May 16, 2011

Using the DataGrid typicalItem to Define Column Widths

This article demonstrates using the DataGrid typicalItem property to initialize column widths and the invalidateTypicalItem() method to notify the DataGrid about typicalItem property changes.

The DataGrid's typicalItem is used to compute the initial width of each GridColumn that doesn't specify an explicit width.  Although specifying absolute sizes in Flex applications is commonplace, it can be perilous.  This is particularly true for components like DataGrid that rely on a separate renderer (factory) to produce the visual element that displays an individual cell.  A carefully contrived explicit column width can be invalidated by  a host of factors: implicit renderer changes, e.g. due to inherited styles, explicit renderer changes, all of the usual margin/padding and other layout configuration changes, as well as text and text format localizations.  An explicit column size's web of dependencies is difficult to manage, particularly in the latter stages of application development. The DataGrid typicalItem property specifies column widths indirectly.

The typicalItem's value is a representative data item that's used to construct and measure "typical" item renderers when the DataGrid's measured size is computed.  If a typicalItem wasn't specified, then the first dataProvider item is used.  To compute column widths, a typical renderer is created and validated for each column, its preferred size is recorded, and then the renderer added to the DataGrid's internal free-list. The preferred sizes define the column widths for GridColumn's that don't specify an explicit width, and the DataGrid's rowHeight.

The advantage of basing column widths on the typicalItem, instead of specifying explicit GridColumnwidths, is that doing so takes all of the factors enumerated earlier into account at runtime, when their final values are known.  It eliminates the guess-work inherent in using explicit column widths, or specifying an explicit value for rowHeight.

Here's an example of a DataGrid that specifies a typicalItem.


<s:DataGrid id="dataGrid" requestedRowCount="5" verticalCenter="0" horizontalCenter="0">
    <s:typicalItem>
        <s:DataItem key="99999" name="Typical Item" price="123.45" call="false"/>
    </s:typicalItem>

    <s:ArrayCollection id="items">
        <s:DataItem key="1000" name="Abrasive" price="100.11" call="false"/>
        <s:DataItem key="1001" name="Brush" price="110.01" call="true"/>
        ...
    </s:ArrayCollection>
</s:DataGrid>


When the DataGrid's width is unconstrained, as it is in this example, then its overall width is essentially the sum of the column widths.  If the DataGrid's width is constrained, for example if left and right are specified, then the typicalItem column widths may be padded so that all of the available horizontal space is allocated.

Here's a running version of the example, and the source code.  Use the input fields at the top of the application to change typicalItem properties.
DataGridTypicalItemExample.mxml

When the application is initialized we insert the typicalItem at the beginning of the DataProvider to help visualize the impact of typicalItem changes. Usually the typicalItem is not displayed.   The code that does this is part of the s:Application tag:

    applicationComplete="items.addItemAt(dataGrid.typicalItem, 0)"


Because typical item column widths are cached, it's necessary to notify the DataGrid when the typicalItem has changed. This is done by calling the DataGrid invalidateTpyicalItem() method. In this example each input field calls invalidateTypicalItem() when a typicalItem property is changed.

No comments:

Post a Comment