I'm rather new to Flex: my training began a pair of months ago. Last two weeks at Comtaste we were involved in reskinning an old application we decided to update and restyle. So, it was my first time skinning an application not for training purposes. We all already know that real world issues are slightly more subtle than the toy situations proposed in many books. So, enough talking and let's go straight to the problem.
In this example, I'm listing some people in a Datagrid component and I want to provide the user with some controls on the record, using two buttons in two separate datagrid columns.
I'm using Flex Builder, so I'll begin creating a Flex project with the following directory structure:

The file src/RenderersMadness.mxml contains the following code, that implements a list with some buttons and data inside.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
applicationComplete="init()"
layout="absolute"
>
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var dataArray:ArrayCollection;
private function init():void
{
dataArray = new ArrayCollection(
[
{
name: "Peter",
surname: "Venkman"
}
,
{
name: "Egon",
surname: "Spengler"
}
,
{
name: "Ray",
surname: "Stantz"
}
]
)
}
]]>
</mx:Script>
<mx:DataGrid dataProvider="{dataArray}">
<mx:columns>
<mx:DataGridColumn dataField="name" headerText="First Name"/>
<mx:DataGridColumn dataField="surname" headerText="Surname"/>
<mx:DataGridColumn headerText="Intern him">
<mx:itemRenderer>
<mx:Component>
<mx:Button label='Intern him' />
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
<mx:DataGridColumn headerText="Slime him">
<mx:itemRenderer>
<mx:Component>
<mx:Button label='Slime!'/>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
</mx:Application>
The program has the following appearance:

It is ok, but I may want to add some exciting graphics and colors to customize my application. So i'm going to use the style properties of the Button component to make a stylish application, by adding the following code:
...
<mx:Button label='Intern him'
fillColors="[0xff0000, 0xcc0000]"
themeColor="0xff0000"
color="0x00BBFF"/>
...
and, by storing the icon image file in the directory assets,
...
<mx:Button label='Slime!'
fillColors="[0x00ff00, 0x00cc00]"
color="0x0000ff"
icon="@Embed(source='../assets/slimer.gif')"
themeColor="0x00ff00"
/>
...
and I'm done. Here's how the component should look now:

Looks fine, but the underlying code gives headaches. I want it to deal just with functional related issues. I don't want strange style properties whose values make the overall code look like some kind of cryptic and geeky script, and most of all, if I'm using the same style properties over a large project I don't want to repeat all of them for all the buttons in my code using such style settings.
An elegant way to separate and loosely couple graphic content such as skinning of components from functional content is to use the styleName property of Flex components and define all that concerns the style business in a .css file. I thought it was straightforward but our application makes a massive use of item renderers to show exotic and unconventional, but useful and comprehensible, representation of data in datagrids and lists. Returning to the example, I could write a CSS file (style/excitingStyle.css) to factorize the style information:
/* CSS file */
Button
{
fillColors: #ff0000, #cc0000;
themeColor: #ff0000;
color:#00BBFF;
}
.slimeButton
{
fillColors: #00ff00, #00cc00;
color:#0000ff;
icon: Embed(source="../assets/slimer.gif");
themeColor: #00ff00;
}
and import it in src/RenderersMadness.mxml, before the
...
<mx:Style source="../style/excitingStyle.css"/>
...
Then I can get rid of all these creepy style in the Button components, specifying just the slimeButton style for the Slime! button.
...
<mx:Button label='Intern him' />
...
<mx:Button label='Slime!' styleName='slimeButton'/>
...
But it won't work! The resulting datagrid in fact seems to ignore the styleName property.

Luckily, I found the solution to this problem. All that is needed is to enclose the component whose styleName property one wants to modify in a Box component:
...
<mx:HBox width="100%">
<mx:Button label='Slime!' width="100%" styleName='slimeButton'/>
</mx:HBox>
...
And here's how the list will look like:

The presence of the Box allows furthermore to define the component's position inside the cell. Suppose I want to drop the label "Slime!" and leave just the rather self-explanatory (at least, for me!) slimer icon. I can do the following, known the icon would be 20 pixels large:
...
<mx:HBox horizontalAlign="center" width="100%">
<mx:Button width="20" styleName='slimeButton'/>
</mx:HBox>
...
Note that I've dropped the label property and I added the horizontalAlign property of the HBox by giving it the value "center", which centers the elements in the box, resulting in the following look:

So in conclusion, enclosing the component we want to use as ItemRenderer in a Box gives two advantages:
1. It is possible to use the styleName property to load styles from external css as in the rest of application.
2. It is possible to position the ItemRenderer in the cell area.
Comments (4)
Hm... I once read that using boxes to align itemrenderers is not the best thing when it comes to performance.
It is better to use an AS itemrenderer an position the button there according to the width and height.
Otherwise you might end up ith hundreds of unnecessary boxes ind large applications with a lot of data.
Posted by Roman | February 25, 2009 1:43 PM
Posted on February 25, 2009 13:43
You're right and I appreciate your comment, however I wanted to stress the fact that something that should be straightforward as styling item renderers needs some kind of workaround in MXML like I described in the post.
Posted by Gabriele Paganelli | March 4, 2009 10:10 AM
Posted on March 4, 2009 10:10
performance is good.keep it up man.
Posted by prolifics | March 7, 2009 6:21 AM
Posted on March 7, 2009 06:21
Thanks for the post! I was stuck due to my Button ignoring the "styleName" attribute. Enclosing in an HBox fixed it!
Posted by Tucker Watson | April 26, 2010 5:24 PM
Posted on April 26, 2010 17:24