« Automatic serialization of ActionScript objects to and from XML | Main | Spring official courses in Italy: Comtaste offers discount code »

Styling ItemRenderers in Datagrids

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:

projtree.gif

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:

nostile.gif

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:

stilenocss.gif

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 tag:


...
<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.

cssnohbox.gif

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:

final.gif

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:

final2.gif

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.

TrackBack

TrackBack URL for this entry:
http://blog.comtaste.com/mt-tb.cgi/83

Comments (4)

Roman:

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.

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.

prolifics:

performance is good.keep it up man.

Tucker Watson:

Thanks for the post! I was stuck due to my Button ignoring the "styleName" attribute. Enclosing in an HBox fixed it!

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

About

This page contains a single entry from the blog posted on February 23, 2009 12:43 PM.

The previous post in this blog was Automatic serialization of ActionScript objects to and from XML.

The next post in this blog is Spring official courses in Italy: Comtaste offers discount code.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.33