Hi All:

I have a use case where different kinds of items are displayed within a single control like an <mx:List> or <mx:Tree>. Based on a descriminator field in each of the data items added to the control, an appropriate itemRenderer is used to display each kind of item correctly.

In the mx.controls.listClasses.ListBase class, an 'itemRenderer' property can be used to set a custom renderer class which is then used for all items in the control, but there does not seem to be a way to choose the itemRenderer /conditionally/ based on the data items. Trying to implement this functionality in a custom ClassFactory is not possible because it doesn't have any access to the data item. So I ended up subclassing <mx:Tree> and overriding ListBase.getItemRendererFactory() like this:

private const commFac:ClassFactory = new ClassFactory(ResultTreeItemRenderer);

override public function getItemRendererFactory(data:Object):IFactory {
var result:IFactory = super.getItemRendererFactory(data); // the default renderer
    var item:ResultItem = data as ResultItem;

    if (item) {
        switch (item.type) {
            case "community":
            case "project": {
                result = commFac;
                break;
            }
        }
    }

    return result;
}

ResultItem is my simple VO having a 'type' field. ResultTreeItemRenderer is my custom renderer based on <s:MXTreeItemRenderer/> which knows how to render ResultItems that are communities or projects. Items of other types get rendered by the default renderer class.

This approach seems like it works, but when I toggle a disclosure node on the tree, often the wrong itemRenderer is used to draw subordinate items that become visible. When there is enough content in the tree/list, scrolling affected items off the visible area awill often cause the correct renderer to be chosen when that item is redrawn after more scrolling to make it visible again, per the code above.

I think the problem is related to how ListBase tries to keep memory consumption down by caching and reusing itemRenderer instances. The ListBase.addToFreeItemRenderers() and ListBase.getReservedOrFreeItemRenderer() methods seem to maintain multiple lists of itemRenderers available for reuse based on which IFactory was used to create the renderer. This implies that it is reasonable to use multiple renderers in the same control. But it's not clear to me why the wrong type of renderer is sometimes used from the cache when items become visible (after toggling a disclosure node). It's also not clear to me why scrolling affected items so as to make them invisible/visible seems to then cause the right renderer to be used. Reading List.makeRowsAndColumns() and List.createItemRenderer() aren't giving me any insights either.

Am I approaching this the right way? Are there other options for doing conditional rendering?

Thanks for any help you can provide,
Jason

Reply via email to