I'm using a tree control that I want to customize. The data items in the tree's dataProvider
have a property name
that should be used for labeling the node, and a property type
that should be used to select one of several embedded images for use as an icon. The simplest way to do this is by using the labelField
and iconFunction
properties.
However, I wanted to get started with item renderers and open the door for adding more complex customization later, so I tried making my own item renderer. I extended the TreeItemRenderer
class as follows and used it in my tree control:
class DirectoryItemRenderer extends TreeItemRenderer
{
[Embed("assets/directory/DefaultIcon.png")]
private static var _DEFAULT_ICON:Class;
// ... some more icons ...
override public function set data(value:Object):void
{
super.data = value; // let the base class take care of everything I didn't think of
if (value is Node) { // only handle the data if it's our own node class
switch ((value as Node).type) {
// ... some case clauses ...
default:
this._vSetIcon(_DEFAULT_ICON);
}
this.label.text = (value as Node).name;
}
}
private function _vSetIcon(icon:Class):void
{
if (null != this.icon && this.contains(this.icon)) {
this.removeChild(this.icon);
}
this.icon = new icon();
this.addChild(this.icon);
this.invalidateDisplayList();
}
}
This code has no effect whatsoever, icon and label in the tree control remain at their defaults. Using trace()
, I verified that my code is actually executed. What did I do wrong?
Best Answer
Looking at the base
mx.controls.treeClasses.TreeItemRenderer
class, I see that in theupdateDisplayList
function the renderer gets it'sicon
anddisclosureIcon
classes from_listData:TeeListData
. Instead of overriding theupdateDisplayList
function, try modifying theicon
anddisclosureIcon
classes of the renderer's private_listData
instance in your_vSetIcon
method using the public accessors, like so:EDIT
Here is some clarification on the difference between
data
andlistData
. You'll have to excuse my omission of package names but I'm editing from my phone so its tough to look them up and I don't know the package names off the top of my head.data
is defined in the context of aTreeItemRenderer
in theIDataRenderer
interface. You create a data renderer by implementing this interface and defining a public propertydata
, which in this case is set by the parent control and contains some data and meta-data from thedataProvider
to be rendered by the data renderer class.listData
is defined in theIDropInListItemRenderer
interface as a property of typeBaseListData
and is realized in theTreeItemRenderer
class as a propertyTreeListData
. It differs from thedata
property in that it contains meta-data that describes theTreeListRenderer
itself (icon, indent, open) as well as (I believe, I'll have to double check this later) a reference to the data item being rendered. I gather that It's used by the theTreeItemRenderer
and I would imagine the parent list control for display update and sizing purposes. Someone is free to correct or add onto that if I'm incorrect or missed something, I'm going of what I remember drom the code.In this case, you wanted to use meta-data from the data set from the data provider to modify data that determines the display of the renderer, so you would need to modify both.
I think the real confusion here however came from the fact that you extended the
TreeItemRenderer
class then tried to override functionality on the component in a manner the original developer didn't intend for someone to do, hence the unexpected results. If your goal is education and not ease of implementation you would probably be better served by extending theUIComponent
class and using theTreeItemRenderer
code as a reference to create a class that implements the same interfaces. That would be a real dive into the pool of custom component development.