ItemRenderers within DataGrids in Flex seem to be a topic that is often discussed and often struggled with. This is my attempt at a short and sweet explanation/example to get newcomers up-to-speed. This will also address the issues many people have with inconsistent rendering during scrolling and sorting of their DataGrid. Check out this example (right-click for source) and do as much clicking, scrolling and sorting as you want. Things should stay in the correct state regardless of how hard you bang on it.

There are three basic parts involved in successfully implementing IRs in DGs. The first is dispatching an event when the user interacts with the IR. This is a pretty straightforward step, but there do seem to be some differing opinions on exactly what and how information should be attached to the event. Let's look at my IR component, SimpleItemRenderer.mxml.

<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" horizontalAlign="center">
    <mx:Script>
        <![CDATA[
            // this override is essential for preventing random (un)checking when your DataGrid is scrolled
            override public function set data(value:Object):void
            {
                // not sure of the details on when or why, but sometimes this method is passed a null value
                if(value != null)
                {
                    super.data = value;
                    // set itemRenderer's state based on data value
                    cb.selected = value.isKnown;
                }
            }

            // local click handler that dispatches the event
            // so it can be handled in a  more appropriate place (such as the document holding the DataGrid)
            private function onClick(e:MouseEvent):void
            {
                // attach our VO onto the event so that it can be manipulated in the handler
                // wherever that handler may be
                var evt:SimpleClickEvent = new SimpleClickEvent(super.data);
                dispatchEvent(evt);
            }
        ]]>
    </mx:Script>
    <mx:CheckBox id="cb" click="onClick(event)" width="15"/>
</mx:HBox>

As you can see, it is simply a CheckBox inside of an HBox. Using an HBox allows me to center the CheckBox and take advantage of other layout conveniences if I need to. I've declared a click handler for the CheckBox but its purpose is really just to package whatever data we need and pass it up the chain via dispatchEvent. You'll notice a reference to super.data, which refers to the item from your dataProvider that was passed to this row of the DataGrid. If we weren't worried about things like loose coupling we could simply update our data from here and be done with it. However, to promote modularity we will simply attach this data to our SimpleClickEvent and let it bubble up to a component that is better suited to handle the user interaction and any associated logic.

That better suited component is usually the container that is holding your DataGrid. Here is the event handler that will ultimately be fired when a user clicks on our IR's CheckBox:

// this is the function that will catch the click event
// that will bubble up from the Checkbox in our DataGrid's itemRenderer
private function onSimpleClickEvent(e:SimpleClickEvent):void
{
    // create refs to the items we care about
    var ir:SimpleItemRenderer = e.target as SimpleItemRenderer;
    var cb:CheckBox = ir.cb as CheckBox;
    var personVO:PersonVO = e.vo as PersonVO;

    // update the appropriate data property based on the CheckBox's selected state
    if(cb.selected)
    {
        personVO.isKnown = true;
    }
    else
    {
        personVO.isKnown = false;
    }
}

The important things to note here are that we are finally checking the type of our event's data payload, which is PersonVO. In our SimpleItemRenderer and SimpleClickEvent we avoided depending on any specific type so that they can be reused in other contexts. We then update the appropriate value in our dataProvider based on the state of our CheckBox. This is an essential step, as it records what the on-record value of this item should be for future reference.

The third and final step in our (very) basic implementation will be one such future reference and is necessary to maintain predictable behavior in the ItemRenderer, particularly if the DataGrid scrolls. This is because of the way DataGrids actually work behind-the-scenes. If your DataGrid's dataProvider has 100 items, but it is only big enough to display 10 at any given time, the DataGrid only actually draws 10 items, in order to maximize performance. When you scroll the DataGrid there aren't any new items being drawn, it is simply swapping the data properties between the already drawn items. So scrolling down one row means that the piece of data for the second item is switched to be the data for the first item, the second item receives the third item's data, and so on and so on. During these reassignments, things like whether or not the CheckBox should be checked get all messed up. Some get checked, some get unchecked... its completely unpredictable. To handle this problem, we must override the data's setter method and use our own logic to determine whether or not the CheckBox should be checked. Here is the relevant piece from SimpleItemRenderer (also shown above).

// this override is essential for preventing random (un)checking when your DataGrid is scrolled
override public function set data(value:Object):void
{
    // not sure of the details on when or why, but sometimes this method is passed a null value
    if(value != null)
    {
        super.data = value;
        // set itemRenderer's state based on data value
        cb.selected = value.isKnown;
    }
}

Yes, this is somewhat tightly coupled to this particular usage since we are assuming value has an isKnown property. I haven't figured out the best way to get around this dependency yet but am leaning towards creating an interface or a generic superclass and having all of my ItemRenderers implement/extend it. To see the scrolling wackiness in action just comment out this method.

OK, so I lied. This definitely wasn't a short explanation, but hopefully it will prove thorough and clear enough to help someone else get their head around using ItemRenderers in Flex.