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