To the naysayers of MXML / “I don’t see that it’s any better if I can write it all out myself in AS” / progress antagonists, if you’re the type to write ItemRenderers and/or ItemEditors this is where you single-handedly loose in time & money, readability, code quality. Every time. (Those who I previously worked for should seriously pay attention -free lesson here -but they never paid attention to me the 1st time around =) .

Thank God for colleagues who feed you tidbits of info just at the right time. In developing the ‘FlexPress’ Theme Application, I had a need to write a custom itemRenderer for a List class to not only display the typical text label, but a check box to make it a bit easier to visually represent multiple selections (and to not have to force the user to understand a CTRL-click even if they already know about it), as well as, a few other nice-to-have GUI expressions. Knowing the drudgery of previous itemRenderers for Flash (I wrote a few for MX/MX04 controls) I ignorantly thought it was going to be yet another chore. Boy was I wrong. Kudos to the engineering team that finally got this one right.

By far the easiest (clearly the fastest) way to write a renderer control is in your MXML gui portion (you are using mxml right?) is to reference the itemRenderer property in a separate child tag. Here’s where the compiler magic comes in, even though it’s not listed in the mxml-manifest.xml file, building a tag will invoke a bunch of different things based on it’s context. You are now free to build *ANYTHING* as a itemRenderer. Heck, it gets even better that you can implement a drop-in renderer interface and gain property/method access to the control itself.

Here’s a few pointers:

  • Want to make it reusable: You’re not required to declare a component tag as a child of the itemRenderer. If you write the component tag as part of the document level you can specify it’s AS class name which then can be re-referenced back to just about anywhere as part of a custom mxlns. Already thinking about subclassed custom renderers? Good.
  • Need data from anything other than the itemRenderer scope: The compiler understands a property called: outerDocument to which it assigns scope from the outside should you write your renderer as child tag.
  • Scope is internal to the renderer: Containment is limited to any control in the renderer, but can easily reference anything in the control itself by implementing the appropriate IDropInRenderer interface. This will allow you access to data in renderer instances around the current one, as well as the control.
  • Have completely custom components that you want to use in a renderer: Implement the simple IDataRenderer interface which allows a dataProvider (ListCollectionView) to attach a reference to the current item

Here’s a snippet example of the one I wrote:

<![CDATA[
<mx:List id=“postList” width=“100%” dataProvider=“{this.listDataProvider}”
                allowMultipleSelection=“true” doubleClickEnabled=“true”
                itemDoubleClick=“onAddSinglePost(event);” itemClick=“onListSelectionChange(event);”>
                        <mx:itemRenderer>
                                <mx:Component className=“CheckLabelItemRenderer”>
                                        <mx:HBox implements=“mx.controls.listClasses.IDropInListItemRenderer”
                                                width=“100%” horizontalScrollPolicy=“off”>
                                               
                                                <mx:Script>
                                                        <![CDATA[
                                                                import flash.events.Event;
                                                               
                                                                import mx.controls.listClasses.BaseListData;
                                                                import mx.controls.List;
                                                                import mx.collections.IList;
                                                       
                                                                private var bld:BaseListData;
                               
                                                                public function get list():List { return this.owner as List; }
                                                               
                                                                [Bindable(“dataChange”)]
                                                                public function get listData():BaseListData {  return bld; }
                                                               
                                                                public function set listData(value:BaseListData):void { bld =value; }
                                                               
                                                               
                                                                public function onBoxSelectionChange():void {
                                                                        var indexMgr:Array =outerDocument.selectedItemRendererIndicies;
                                                                       
                                                                        if (this.selectedCheck.selected) { indexMgr.push(this.listData.rowIndex); }
                                                                        else {
                                                                                var n:int =indexMgr.length;
                                                                                for (var i:int=0;i<n;i++) {
                                                                                        if (indexMgr[i] ==this.listData.rowIndex) {
                                                                                                indexMgr.splice(i,1);
                                                                                                break;
                                                                                        }
                                                                                }
                                                                        }
                                                                        trace(‘onBoxSelectionChange ‘+indexMgr);
                                                                        this.list.selectedIndices =indexMgr.concat();
                                                                }
                                                               
                                                        ]]>
                                                </mx:Script>
                                               
                                                <mx:CheckBox id=“selectedCheck” />
                                                <mx:Label text=“{data.title}” />
                                        </mx:HBox>
                                </mx:Component>
                        </mx:itemRenderer>     
        </mx:List>
]]>