26 novembre 2009
Imprimer ce billet

Flex : Custom style DataGrid


Lors de la finalisation de l'un de nos développements Flex, nous avons mis en place des styles pour les différents composants de l'application. Mais il se trouve que nous avons rencontré une petite difficulté sur le composant DataGrid. A noter également l'utilisation de Flex 4 dans cet exemple, mais ce problème est aussi valable avec Flex 3.

 

Les styles

Avec Flex, les styles sont très simples à mettre en place, et se font de la même manière qu'en HTML :

  • Soit via la définition des styles directement dans le fichier MXML :
<mx:Style>
    myStyle {
        fontFamily: "arial";
        background-color:#FFFFFF;
    }
</mx:Style>

  • Soit via la définition d'une feuille de styles CSS, déclarée dans le fichier MXML :
<mx:Style source="css/xebia.css"/>

Concernant le composant DataGrid, modifier les couleurs des lignes devient trivial avec la propriété alternatingItemColors. Néanmoins la situation se corse lorsque nous devons appliquer ces couleurs aux lignes d'une seule colonne...

Exemple

Prenons un exemple :

XebiaCustomDataGrid1.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/halo" minWidth="1024" minHeight="768">

    <fx:Script>
    <![CDATA[
            import mx.collections.ArrayCollection;
            [Bindable]
            public var xebia:ArrayCollection = new ArrayCollection([
                {Company:"Xebia France", City:"Défense", Benefits:200000},
                {Company:"Xebia Hollande", City:"Hilversum", Benefits:400000},
                {Company:"Xebia Inde", City:"New Dehli", Benefits:150000},
                {Company:"Xebia US", City:"New York", Benefits:500000},
                {Company:"Xebia Allemagne", City:"Berlin", Benefits:160000},
                {Company:"Xebia Espagne", City:"Barcelone", Benefits:80000},
                {Company:"Xebia Portugal", City:"Lisbonne", Benefits:75000},
                {Company:"Xebia Italie", City:"Milan", Benefits:110000}
            ]);
        ]]>

    </fx:Script>

    <mx: DataGrid dataProvider="{xebia}" sortableColumns="false" selectable="false" height="228" width="515">
        <mx:columns>
            <mx: DataGridColumn headerText="Company" dataField="Company"/>
            <mx: DataGridColumn headerText="City" dataField="City"/>
            <mx: DataGridColumn headerText="Benefits" dataField="Benefits"/>
        </mx:columns>
    </mx: DataGrid>

</s:Application>

Dans cet exemple, nous avons un simple DataGrid remplit avec une ArrayCollection, et dont les lignes ont des couleurs alternées.


Dans ce second exemple, nous ajoutons une CSS :

xebia.css

.grid {
    alternatingItemColors: #ffccff, #ff99cc;
}

.header {
    fontWeight: bold;
}

XebiaCustomDataGrid2.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/halo" minWidth="1024" minHeight="768">

    <fx:Style source="css/xebia.css"/>

    <fx:Script>
    <![CDATA[
            import mx.collections.ArrayCollection;
            [Bindable]
            public var xebia:ArrayCollection = new ArrayCollection([
                {Company:"Xebia France", City:"Défense", Benefits:200000},
                {Company:"Xebia Hollande", City:"Hilversum", Benefits:400000},
                {Company:"Xebia Inde", City:"New Dehli", Benefits:150000},
                {Company:"Xebia US", City:"New York", Benefits:500000},
                {Company:"Xebia Allemagne", City:"Berlin", Benefits:160000},
                {Company:"Xebia Espagne", City:"Barcelone", Benefits:80000},
                {Company:"Xebia Portugal", City:"Lisbonne", Benefits:75000},
                {Company:"Xebia Italie", City:"Milan", Benefits:110000}
            ]);
        ]]>

    </fx:Script>

    <mx: DataGrid dataProvider="{xebia}" sortableColumns="false" selectable="false" styleName="grid" headerStyleName="header" height="228" width="515">
        <mx:columns>
            <mx: DataGridColumn headerText="Company" dataField="Company"/>
            <mx: DataGridColumn headerText="City" dataField="City"/>
            <mx: DataGridColumn headerText="Benefits" dataField="Benefits"/>
        </mx:columns>
    </mx: DataGrid>

</s:Application>

On notera l'ajout des attributs styleName et headerStyleName dans les propriétés du DataGrid, ainsi que de la déclaration de la CSS :

<fx:Style source="css/xebia.css"/>

Nous obtenons ainsi le rendu suivant :


Mais que faire si nous voulons appliquer un style sur une seule colonne ? La solution consiste à surcharger les cellules de la colonne concernée par un renderer. Pour ce faire, une classe ActionScript doit être mise en place.

Voici la classe CustomCell.as :

public class CustomCell extends Label 
     {

      override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            super.updateDisplayList(unscaledWidth, unscaledHeight);
            var g:Graphics = graphics;
            g.clear();

            if (DataGridListData(listData).rowIndex % 2 == 0) {
                g.beginFill(0xffdfbf);
            } else {
               g.beginFill(0xffc080);
               
            }
            g.drawRect(0, -2, unscaledWidth+1, unscaledHeight+4);
            g.endFill(); 
        }   
     }

Ainsi pour chaque ligne, nous dessinons un rectangle dans la cellule avec la même alternance de couleurs.
Il ne nous reste plus qu'à appliquer ce renderer au DataGrid.

XebiaCustomDataGrid3.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/halo" minWidth="1024" minHeight="768">

    <fx:Style source="css/xebia.css"/>

    <fx:Script>
    <![CDATA[
            import mx.collections.ArrayCollection;
            [Bindable]
            public var xebia:ArrayCollection = new ArrayCollection([
                {Company:"Xebia France", City:"Défense", Benefits:200000},
                {Company:"Xebia Hollande", City:"Hilversum", Benefits:400000},
                {Company:"Xebia Inde", City:"New Dehli", Benefits:150000},
                {Company:"Xebia US", City:"New York", Benefits:500000},
                {Company:"Xebia Allemagne", City:"Berlin", Benefits:160000},
                {Company:"Xebia Espagne", City:"Barcelone", Benefits:80000},
                {Company:"Xebia Portugal", City:"Lisbonne", Benefits:75000},
                {Company:"Xebia Italie", City:"Milan", Benefits:110000}
            ]);
        ]]>

    </fx:Script>

    <mx: DataGrid dataProvider="{xebia}" sortableColumns="false" selectable="false" styleName="grid" headerStyleName="header" height="228" width="515">
        <mx:columns>
            <mx: DataGridColumn headerText="Company" dataField="Company"/>
            <mx: DataGridColumn headerText="City" dataField="City"/>
            <mx: DataGridColumn headerText="Benefits" dataField="Benefits" itemRenderer="renderer.CustomCell"/>
        </mx:columns>
    </mx: DataGrid>

</s:Application>

Nous remarquons que la propriété itemRenderer a été ajoutée sur la troisième colonne du DataGrid.

Ainsi nous obtenons le rendu suivant :


Enfin à travers cet exemple nous revoyons une des limites de Flex: malgré la richesse des composants et de leurs comportements, lorsque les développements deviennent un peu plus subtils, du code ActionScript est nécessaire, là où dans cet exemple une simple instruction CSS aurait suffit...

En espérant que cette solution puisse aider d'autres personnes !

Vous pouvez télécharger les sources sur le SVN de Xebia France.

Mots-clefs :,