Tuesday, December 1, 2009

Flex Array vs ArrayCollection

I have been teaching myself flex for the past few years now and I finally have a firm grasp on how arrays should be used, and the difference between an ArrayCollection and an array.

People like to just assume that if your using Flex that you should just know all about event driven programming, well, I didn't, I came from procedural programming, and still today prefer it.

Well, for those that want to know whats so special about an ArrayCollection, here it is...

A basic Array (not ArrayCollection) is a primitive object, it has no special abilities whatsoever, it is just an array, where on the other hand, an ArrayCollection is an EventDispatcher and also has alot of nice extras that come in handy.

If you are trying to make a propery to be bound to, use an ArrayCollection, and don't be lazy, perform updates to it, do not "removeAll", and then re-add items to it, you will get all sorts of UI glitches if you do.

When items are added/removed from an array collection a "CollectionChangeEvent" is dispatched, this can be VERY handy. For example, drag and drop can be a nightmare to get right between controls, and so many people over complicate the whole mess.

If you listen for the CollectionChangeEvent and just set the "dragEnable", "dragMoveEnable" and "dropEnable" properties of your two controls, you will recieve "ADD" and "REMOVE" events when items are dragged into and out of the ArrayCollection.

If you implement these add/remove events you can bind the collections to user objects without a single line of code in the front end.

Anyway, enough theory, here is some example code:

*Note, this is psuedo code

public class MyClass {
private var _dp1: ArrayCollection = new ArrayCollection();
private var _dp2: ArrayCollection = new ArrayCollection();

public function myClass(Items: Array): void {
for each(var o: Object in Items) {
_dp1.addItem(o);
}
_dp1.addEventListener(CollectionEvent.COLLECTION_CHANGE, e_collectionChange);
}

private function e_collectionChange(event: CollectionChangeEvent): void {
var o: Object;
switch(event.kind) {
case CollectionChangeEventKind.ADD:
for each(o in event.items) {
if (_dp2.contains(o))
_dp2.removeItemAt(_dp2.getItemIndex(o));
}
break;

case CollectionChangeEventKind.REMOVE:
for each(o in event.items) {
if (!_dp2.contains(o))
_dp2.addItem(o);
}
break;
}

[Bindable]
public function get dataProvider(): ArrayCollection {
return _dp1;
}

[Bindable]
public function get removedItems(): ArrayCollection {
return _dp2;
}
}
}

This class will automatically maintain a a 2nd data provider "removedItems" as the dataProvider has its items removed/added, not very useful, but a good example. It could be bound to two lists with drag/drop properties set. Usage is simple:

<mx:Application creationComplete="init()">
<mx:Script>
private var myclass: MyClass;
private function init(): void {
myclass = new MyClass([1, 2, 3, 4]);
}
</mx:Script>
<mx:VBox>
<mx:Label label="Drag Between">
<mx:HBox>
<mx:List dataProvider="{myClass.dataProvider}" dragEnabled="true" dropEnabled="true" dragMoveEnabled="true"/>
<mx:List dragEnabled="true" dropEnabled="true" dragMoveEnabled="true"/>
</mx:HBox>
<mx:Label label="Removed Items">
<mx:List dataProvider="{myClass.removedItems}"/>
</mx:VBox>
</mx:Application>


In my next post I will describe how to use this to create a class that tracks changes for submission to a back end server, using a mix of both Arrays and ArrayCollections.

No comments:

Post a Comment