Last week I posted an article showing how to create type-safe lists for use as Flex List-based DataProviders. This week I’m enhancing that example to dispatch events when items are added to or removed from the collection. This will allow Lists to update their displays automatically whenever the contents of the DataProvider change. If you haven’t already read my previous post on this topic, you will probably want to do so before continuing with this one.
This application wraps a Vector object in a class to provide type-safe access. This class implements IList so that the List, ComboBox and DropDownList can use it as a DataProvider. Right-click the app to view source or download an FXP file here.
Improved IList Type-Safety
But before I get to dispatching events I’d like to point out another improvement I’ve made to the PersonVectorDP example class which strictly enforces the type-safe approach. In last week’s post I recommended using only IPersonVectorDP to provide type-safe access. And I recommended setting the reference to the PersonVectorDP class to null as soon as possible to prevent accidental access through the IList methods:
_people = new PersonVectorDP; peopleList.dataProvider = _people; // Always access PersonVectorDP only through IPersonVectorDP _peopleInterface = _people as IPersonVectorDP; _people = null; // To be safe, null this out ASAP. That way, you can't inadvertently use the wrong method.
This approach will work but still requires some diligence on the part of the developer. It subsequently occurred to me that a better approach is to enforce modification of the collection through the IPersonVectorDP interface by throwing an exception if any attempt is made to modify the collection through the IList methods. So, for example, instead of implementing addItem by pushing the new Person onto the Vector, we now throw an IllegalOperationError instead:
throw new IllegalOperationError("addItem - no access through IList; use IPersonVectorDP instead");
I’ve done the same thing for all the other IList methods which modify the list. Of course, the getItemAt and getItemIndex methods are unchanged.
Now, if you forget to null out the PersonVectorDP reference it won’t matter. And, maybe you need to keep the reference around in order to assign it as the DataProvider to some new List later. Now, you can. And you can be certain that all access to the collection will be type-safe. Best of all, the code is smaller and cleaner!
Dispatching collectionChange Events
Continuing with the modified PersonVectorDP class, the next change I’ve made is to have the class extend EventDispatcher:
public class PersonVectorDP extends EventDispatcher implements IList, IPersonVectorDP
This allows us to remove all of the event-related stub code that is present in the previous example (addEventListener, removeEventListener, dispatchEvent, etc.). The class still implements IList & IPersonVectorDP, as before.
We also now declare that the class dispatches the event that List-based controls listen for:
[Event(name="collectionChange", type="mx.events.CollectionEvent")]
And we dispatch this event whenever items are added to the list:
public function push(value:Person):uint { var count:uint = _people.push(value); var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE); event.kind = CollectionEventKind.ADD; event.items.push(value); event.location = count-1; dispatchEvent(event); return count; }
and whenever items are removed from the list:
public function pop():Person { var poppedPerson:Person = _people.pop(); var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE); event.kind = CollectionEventKind.REMOVE; event.items.push(poppedPerson); event.location = _people.length; dispatchEvent(event); return poppedPerson; }
That’s all the changes that are needed to PersonVectorDP. You could, of course, add accessor methods to the IPersonVectorDP for more functionality; e.g., type-safe equivalents to addItemAt or itemUpdated.
Demo Code to Use the Modified PersonVectorDP Class
Next, I’ve made a few changes to the test app, VectorDataProviderTypeSafe.mxml. I’ve added a couple of input fields and a button to allow adding more people. And, I’ve added a button to remove people:
<s:TextInput id="newPersonFirst" /> <s:TextInput id="newPersonLast" /> <s:Button id="addPerson" label="Add Person" click="addPerson_clickHandler(event)" /> <s:Button id="removePerson" label="Remove Person" click="removePerson_clickHandler(event)" />
This button click listener code is straightforward; here’s the add event listener:
protected function addPerson_clickHandler(event:MouseEvent):void { var person:Person = new Person; person.firstName = newPersonFirst.text; person.lastName = newPersonLast.text; _peopleInterface.push(person); }
And here’s the remove event listener:
protected function removePerson_clickHandler(event:MouseEvent):void { _peopleInterface.pop(); }
I hope this technique works to help you write more bug-free code!


{ 2 trackbacks }