ItemRenderers ought to be considered private children of their parent control and get their data from their parent only. Of course sometimes itemRenderers need data beyond what's supplied to them via
IDataRenderer. Imagine that we've a List-based control and want our itemRenderer children to know when some bit of data has changed perhaps
isTheWorldEnding:Boolean. The itemRenderers can then prepare from the upcoming conflagration by changing their states accordingly. I've seen lots of bad solutions to this problem, two common ones are:
- Injecting a Presentation-Model into the itemRenderers (bad)
- referencing an awful Singleton with the desired data (real bad)
Here's a better way. Sub-class the
List control (make a
MyList control) and add a publicly accessible property of
isTheWorldEnding. In
MyList when
isTheWorldEnding is set to a new value, call
invalidateList() to refresh the renderers. Meanwhile, implement
IDropInListItemRenderer in the renderers and get
isTheWorldEnding by casting
_listData.owner as MyList. Here's the code to be put in
MyList:
and the code to be placed in our renderer:
Edit:
Joel pointed out that it would be nice to have a convenient method to cast the list, here it is:
4 comments:
Nice! Might be good to recap why injecting a PM is bad though. It's one of those things everyone kinda knows, but may not entirely know why or what perils exist...
Well the Principle of Least Knowledge (only talk to your immediate friends) is one thing violated by the presentation-model injection approach. Specifically the reason this violation is bad is that our itemRenderers will have a dependency coupling them to a class a few layers removed in the application. A change to the presentation-model can now break our renderers, and that's hardly obvious when you're editing the presentation-model. Also, when a bug is filed against our renderer, we'll have to check the parent List control *and* the presentation-model sifting through those two dependecies to find the data and/or state. I guess I could have summarized this as "it is less maintainable" but what fun would that be? :)
in order for this to work, don't forget to add the following to the renderer:
1:
implements="mx.controls.listClasses.IDropInListItemRenderer" to the renderer
2:
public function get listData():BaseListData
{return _listData;}
These might seem trivial but easy to forget if you're just copying and pasting this example! Hope it helps.
Was "Meanwhile, implement IDropInListItemRenderer in the renderers..." not clear enough? :)
Post a Comment