
The ListBase classes are containers. In their simplest form, they mimic a typical OS list. In this capacity they work fairly well, and I see very little reason to mediate ItemRenderers. But they can be used for things far outside the scope of a typical list. This other use, I will refer to as the “Optimised Continuum Container”. Cool name eh? :)

A “Continuum Container” is any container that presents a collection (the continuum) along an axis (1). VBox and HBox are prime examples. When the continuum get’s long, we need a scrolling mechanism to present the continuum to the user (2).
When the continuum gets very long, we need to ‘Optimise’ the container such that it only instantiates enough children to represent what’s on screen (3). That’s what the ListBase classes do.
We decided that we wanted to present a list of items to the user in such a way that common goals (actions upon the items) were easy to find and use. Lets say its an employee list. Here’s a typical implementation of a list, with actions associated:

Maybe not too typical, this obviously has some design challenges. Common actions for a list item should be readily locatable. One way of doing this is shown above, you keep the actions still (motionless, in one obvious place), and you select the item upon which to act.
When your list window gets large, as ours often do, the travel time with the mouse to the action items becomes frustrating and can cause disorientation. So what we do is (and you’ve seen this many times before) is to group the actions with the list item:

So suddenly we don’t have typical list items. Each list item has more than one “concern” now:
It get’s even more complicated when there are modelled conditions that lie outside the VO, for example, if the user does not have permission to send emails from the application, we don’t want to show the email button.
I personally believe that these concerns should be seperate. When I first saw an example of a view-mediator tuple for a single button, I thought “What horrendous overkill”. Now I’ve been Robotlegging it for a while, I can’t imagine a life less granular, and I always try to get my view/mediator “concern count” near to 1.
If you don’t agree with that last paragraph, then you won’t need to mediate ItemRenderers.
The view for my list item in that example includes several child views (and mediators) for each button. This is so clean and simple to refactor, and to read, that I would not have it any other way (pragmatically speaking).
ItemRenderers and ItemEditors lead a fragile existence and are not straight-forward to mediate. This does not mean you can’t mediate them, it means you must know your enemy.
So when an item goes off the list, it’s renderer does not get destroyed, instead the ‘data’ property is set to a new item and the renderer is moved into place on the list.
This means that you can’t simply rely on instantiation and the event bus to observe when you need to mediate your view. You need to also watch the data property. That’s not so hard now is it?
Typically when you mediate, you establish state on instantiation (if necessary) and modify state as changes come off the event bus (and binding). This means that you establish an accurate reflection of state by knowing the previous “reflection of state” was correct
That’s what makes ItemRenderers a little harder, you need to reset state more often, and there are more gotchas.
For example, when we save an edit on a list item, we tell the Renderer (not the editor) to switch to a busy “spinny circle” state. If the item goes off screen, the Renderer get’s reused for something else, and we must reset it’s state such that it doesn’t look busy. If the item comes back on screen while still saving to the server (hello New Zealand ping times), then we need to reset it’s state to busy.
I’ll try to write a follow up article on best practices for resetting ItemRenderer state.
When an item is editable and the user begins an edit, the ItemRenderer is hidden, and a new ItemEditor is instantiated. This means that whatever mediation you use for the renderer, may well need to be duplicated for the editor. I keep these concerns seperate and look for common code via common refactoring methods (extract*).
Despite all this, we do have a simple set of rules we always follow, no matter the renderer. I’ll spell them out here, and in my next article I’ll show some working code.
© 2010 - VisFleet Ltd
No prawns were harmed in
the making of this website
Comments