Secrets of the Flex 4 SDK [cough] ArrayList.as

Time to pull a McGyver - all we need is a paperclip, some scotch tape, a... scratch that. All we need is ArrayList.as from the Flex 4 SDK.

I've said this many times in the last few years - the real power behind a Flex app comes from extending its base components and classes. A solid foundation can easily turn into something so sweet it will make your teeth hurt. Hobnox anyone?

Ready?

Before we start... there isn't going to be any alchemy today - not today - just a little McGyver. What I really want to do is point you in the right direction and give you some ideas. Hopefully it will spark your creativity and open up some new horizons for you and your interweb solutions.

Lets use ArrayList.as from the Flex 4 SDK. Pretty simple you say? Perhaps... but there are a couple items worth note. Have you ever wondered how change events propagate within the class? Hmm... take a look at the constructor and this bit of candy in it.

  1. disableEvents();
  2. this.source = source;
  3. enableEvents();

I wonder what would happen if you monkey-patched the class and made those methods public or better yet wrapped them up like a bit of salt-water-taffy... just be careful with the increment / decrement of events.

So - what do you have now? The base for a high performance data provider? A mechanism to shim in data without change events firing until your ready? A super-sortable transaction aware data thingy? I don't know... you tell me.

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  ADOBE SYSTEMS INCORPORATED
  4. //  Copyright 2005-2007 Adobe Systems Incorporated
  5. //  All Rights Reserved.
  6. //
  7. //  NOTICE: Adobe permits you to use, modify, and distribute this file
  8. //  in accordance with the terms of the license agreement accompanying it.
  9. //
  10. ////////////////////////////////////////////////////////////////////////////////
  11.  
  12. package mx.collections
  13. {
  14.    
  15. import flash.events.EventDispatcher;
  16. import flash.events.IEventDispatcher;
  17. import flash.utils.IDataInput;
  18. import flash.utils.IDataOutput;
  19. import flash.utils.IExternalizable;
  20. import flash.utils.getQualifiedClassName;
  21.  
  22. import mx.core.IPropertyChangeNotifier;
  23. import mx.events.CollectionEvent;
  24. import mx.events.CollectionEventKind;
  25. import mx.events.PropertyChangeEvent;
  26. import mx.events.PropertyChangeEventKind;
  27. import mx.resources.IResourceManager;
  28. import mx.resources.ResourceManager;
  29. import mx.utils.ArrayUtil;
  30. import mx.utils.UIDUtil;
  31.  
  32. //--------------------------------------
  33. //  Events
  34. //--------------------------------------
  35.  
  36. /**
  37.  *  Dispatched when the IList has been updated in some way.
  38.  *  
  39.  *  @eventType mx.events.CollectionEvent.COLLECTION_CHANGE
  40.  *  
  41.  *  @langversion 3.0
  42.  *  @playerversion Flash 9
  43.  *  @playerversion AIR 1.1
  44.  *  @productversion Flex 3
  45.  */
  46. [Event(name="collectionChange", type="mx.events.CollectionEvent")]
  47.  
  48. //--------------------------------------
  49. //  Other metadata
  50. //--------------------------------------
  51.  
  52. [ExcludeClass]
  53.  
  54. [RemoteClass(alias="flex.messaging.io.ArrayList")]
  55.  
  56. [ResourceBundle("collections")]
  57.  
  58. [DefaultProperty("source")]
  59. /**
  60.  *  @private
  61.  *  A simple implementation of IList that uses a backing Array.
  62.  *  This base class will not throw ItemPendingErrors but it
  63.  *  is possible that a subclass might.
  64.  */
  65. public class ArrayList extends EventDispatcher
  66.            implements IList, IExternalizable, IPropertyChangeNotifier
  67. {
  68.     include "../core/Version.as";
  69.  
  70.     //--------------------------------------------------------------------------
  71.     //
  72.     // Constructor
  73.     //
  74.     //--------------------------------------------------------------------------
  75.  
  76.     /**
  77.      *  Construct a new ArrayList using the specified array as its source.
  78.      *  If no source is specified an empty array will be used.
  79.      *  
  80.      *  @langversion 3.0
  81.      *  @playerversion Flash 9
  82.      *  @playerversion AIR 1.1
  83.      *  @productversion Flex 3
  84.      */
  85.     public function ArrayList(source:Array = null)
  86.     {
  87.                 super();
  88.  
  89.         disableEvents();
  90.         this.source = source;
  91.         enableEvents();
  92.         _uid = UIDUtil.createUID();
  93.     }
  94.    
  95.     //--------------------------------------------------------------------------
  96.     //
  97.     // Variables
  98.     //
  99.     //--------------------------------------------------------------------------
  100.  
  101.         /**
  102.          *  @private
  103.          *  Used for accessing localized Error messages.
  104.          */
  105.         private var resourceManager:IResourceManager =
  106.                                                                         ResourceManager.getInstance();
  107.  
  108.     //--------------------------------------------------------------------------
  109.     //
  110.     // Properties
  111.     //
  112.     //--------------------------------------------------------------------------
  113.    
  114.     //----------------------------------
  115.     // length
  116.     //----------------------------------
  117.  
  118.     /**
  119.      *  Get the number of items in the list.  An ArrayList should always
  120.      *  know its length so it shouldn't return -1, though a subclass may
  121.      *  override that behavior.
  122.      *
  123.      *  @return int representing the length of the source.
  124.      *  
  125.      *  @langversion 3.0
  126.      *  @playerversion Flash 9
  127.      *  @playerversion AIR 1.1
  128.      *  @productversion Flex 3
  129.      */
  130.     public function get length():int
  131.     {
  132.         if (source)
  133.                 return source.length;
  134.         else
  135.                 return 0;
  136.     }
  137.    
  138.     //----------------------------------
  139.     // source
  140.     //----------------------------------
  141.    
  142.     /**
  143.      *  The source array for this ArrayList.  
  144.      *  Any changes done through the IList interface will be reflected in the
  145.      *  source array.  
  146.      *  If no source array was supplied the ArrayList will create one internally.
  147.      *  Changes made directly to the underlying Array (e.g., calling
  148.      *  <code>theList.source.pop()</code> will not cause <code>CollectionEvents</code>
  149.      *  to be dispatched.
  150.      *
  151.          *  @return An Array that represents the underlying source.
  152.      *  
  153.      *  @langversion 3.0
  154.      *  @playerversion Flash 9
  155.      *  @playerversion AIR 1.1
  156.      *  @productversion Flex 3
  157.      */
  158.     public function get source():Array
  159.     {
  160.         return _source;
  161.     }
  162.    
  163.     public function set source(s:Array):void
  164.     {
  165.         var i:int;
  166.         var len:int;
  167.         if (_source && _source.length)
  168.         {
  169.             len = _source.length;
  170.             for (i = 0; i < len; i++)
  171.             {
  172.                 stopTrackUpdates(_source[i]);
  173.             }
  174.         }
  175.         _source  = s ? s : [];
  176.         len = _source.length;
  177.         for (i = 0; i < len; i++)
  178.         {
  179.             startTrackUpdates(_source[i]);
  180.         }
  181.        
  182.         if (_dispatchEvents == 0)
  183.         {
  184.            var event:CollectionEvent =
  185.                         new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
  186.            event.kind = CollectionEventKind.RESET;
  187.            dispatchEvent(event);
  188.         }
  189.     }
  190.    
  191.     //----------------------------------
  192.     // uid -- mx.core.IPropertyChangeNotifier
  193.     //----------------------------------
  194.    
  195.     /**
  196.      *  Provides access to the unique id for this list.
  197.      *  
  198.      *  @return String representing the internal uid.
  199.      *  
  200.      *  @langversion 3.0
  201.      *  @playerversion Flash 9
  202.      *  @playerversion AIR 1.1
  203.      *  @productversion Flex 3
  204.      */  
  205.     public function get uid():String
  206.     {
  207.         return _uid;
  208.     }
  209.    
  210.     public function set uid(value:String):void
  211.     {
  212.         _uid = value;
  213.         }
  214.  
  215.     //--------------------------------------------------------------------------
  216.     //
  217.     // Methods
  218.     //
  219.     //--------------------------------------------------------------------------
  220.  
  221.     /**
  222.      *  Get the item at the specified index.
  223.      *
  224.      *  @param  index the index in the list from which to retrieve the item
  225.      *  @param  prefetch int indicating both the direction and amount of items
  226.      *                  to fetch during the request should the item not be local.
  227.      *  @return the item at that index, null if there is none
  228.      *  @throws ItemPendingError if the data for that index needs to be
  229.      *                           loaded from a remote location
  230.      *  @throws RangeError if the index < 0 or index >= length
  231.      *  
  232.      *  @langversion 3.0
  233.      *  @playerversion Flash 9
  234.      *  @playerversion AIR 1.1
  235.      *  @productversion Flex 3
  236.      */
  237.     public function getItemAt(index:int, prefetch:int = 0):Object
  238.     {
  239.         if (index < 0 || index >= length)
  240.                 {
  241.                         var message:String = resourceManager.getString(
  242.                                 "collections", "outOfBounds", [ index ]);
  243.                 throw new RangeError(message);
  244.                 }
  245.            
  246.         return source[index];
  247.     }
  248.    
  249.     /**
  250.      *  Place the item at the specified index.  
  251.      *  If an item was already at that index the new item will replace it and it
  252.      *  will be returned.
  253.      *
  254.      *  @param  item the new value for the index
  255.      *  @param  index the index at which to place the item
  256.      *  @return the item that was replaced, null if none
  257.      *  @throws RangeError if index is less than 0 or greater than or equal to length
  258.      *  
  259.      *  @langversion 3.0
  260.      *  @playerversion Flash 9
  261.      *  @playerversion AIR 1.1
  262.      *  @productversion Flex 3
  263.      */
  264.     public function setItemAt(item:Object, index:int):Object
  265.     {
  266.         if (index < 0 || index >= length)
  267.                 {
  268.                         var message:String = resourceManager.getString(
  269.                                 "collections", "outOfBounds", [ index ]);
  270.                 throw new RangeError(message);
  271.                 }
  272.        
  273.         var oldItem:Object = source[index];
  274.         source[index] = item;
  275.         stopTrackUpdates(oldItem);
  276.         startTrackUpdates(item);
  277.        
  278.         //dispatch the appropriate events
  279.         if (_dispatchEvents == 0)
  280.         {
  281.                 var hasCollectionListener:Boolean =
  282.                         hasEventListener(CollectionEvent.COLLECTION_CHANGE);
  283.                 var hasPropertyListener:Boolean =
  284.                         hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE);
  285.                 var updateInfo:PropertyChangeEvent;
  286.                
  287.                 if (hasCollectionListener || hasPropertyListener)
  288.                 {
  289.                         updateInfo = new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE);
  290.                         updateInfo.kind = PropertyChangeEventKind.UPDATE;
  291.                 updateInfo.oldValue = oldItem;
  292.                 updateInfo.newValue = item;
  293.                 updateInfo.property = index;
  294.                 }
  295.                
  296.                 if (hasCollectionListener)
  297.                 {
  298.                         var event:CollectionEvent =
  299.                                         new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
  300.                 event.kind = CollectionEventKind.REPLACE;
  301.                 event.location = index;
  302.                 event.items.push(updateInfo);
  303.                 dispatchEvent(event);
  304.                 }
  305.                
  306.                 if (hasPropertyListener)
  307.                 {
  308.                 dispatchEvent(updateInfo);
  309.                 }
  310.         }
  311.         return oldItem;    
  312.     }
  313.    
  314.     /**
  315.      *  Add the specified item to the end of the list.
  316.      *  Equivalent to addItemAt(item, length);
  317.      *
  318.      *  @param item the item to add
  319.      *  
  320.      *  @langversion 3.0
  321.      *  @playerversion Flash 9
  322.      *  @playerversion AIR 1.1
  323.      *  @productversion Flex 3
  324.      */
  325.     public function addItem(item:Object):void
  326.     {
  327.         addItemAt(item, length);
  328.     }
  329.    
  330.     /**
  331.      *  Add the item at the specified index.  
  332.      *  Any item that was after this index is moved out by one.  
  333.      *
  334.      *  @param item the item to place at the index
  335.      *  @param index the index at which to place the item
  336.      *  @throws RangeError if index is less than 0 or greater than the length
  337.      *  
  338.      *  @langversion 3.0
  339.      *  @playerversion Flash 9
  340.      *  @playerversion AIR 1.1
  341.      *  @productversion Flex 3
  342.      */
  343.     public function addItemAt(item:Object, index:int):void
  344.     {
  345.         if (index < 0 || index > length)
  346.                 {
  347.                         var message:String = resourceManager.getString(
  348.                                 "collections", "outOfBounds", [ index ]);
  349.                 throw new RangeError(message);
  350.                 }
  351.                
  352.         source.splice(index, 0, item);
  353.  
  354.         startTrackUpdates(item);
  355.         internalDispatchEvent(CollectionEventKind.ADD, item, index);
  356.     }
  357.    
  358.     /**
  359.      *  @copy mx.collections.ListCollectionView#addAll
  360.      *  
  361.      *  @langversion 3.0
  362.      *  @playerversion Flash 9
  363.      *  @playerversion AIR 1.1
  364.      *  @productversion Flex 3
  365.      */
  366.     public function addAll(addList:IList):void
  367.     {
  368.         addAllAt(addList, length);
  369.     }
  370.    
  371.     /**
  372.      *  @copy mx.collections.ListCollectionView#addAllAt
  373.      *  
  374.      *  @langversion 3.0
  375.      *  @playerversion Flash 9
  376.      *  @playerversion AIR 1.1
  377.      *  @productversion Flex 3
  378.      */
  379.     public function addAllAt(addList:IList, index:int):void
  380.     {
  381.         var length:int = addList.length;
  382.         for(var i:int=0; i < length; i++)
  383.         {
  384.             this.addItemAt(addList.getItemAt(i), i+index);
  385.         }
  386.     }
  387.    
  388.     /**
  389.      *  Return the index of the item if it is in the list such that
  390.      *  getItemAt(index) == item.  
  391.      *  Note that in this implementation the search is linear and is therefore
  392.      *  O(n).
  393.      *
  394.      *  @param item the item to find
  395.      *  @return the index of the item, -1 if the item is not in the list.
  396.      *  
  397.      *  @langversion 3.0
  398.      *  @playerversion Flash 9
  399.      *  @playerversion AIR 1.1
  400.      *  @productversion Flex 3
  401.      */
  402.     public function getItemIndex(item:Object):int
  403.     {
  404.         return ArrayUtil.getItemIndex(item, source);
  405.     }
  406.    
  407.     /**
  408.      *  Removes the specified item from this list, should it exist.
  409.      *
  410.      *  @param  item Object reference to the item that should be removed.
  411.      *  @return Boolean indicating if the item was removed.
  412.      *  
  413.      *  @langversion 3.0
  414.      *  @playerversion Flash 9
  415.      *  @playerversion AIR 1.1
  416.      *  @productversion Flex 3
  417.      */
  418.     public function removeItem(item:Object):Boolean
  419.     {
  420.         var index:int = getItemIndex(item);
  421.         var result:Boolean = index >= 0;
  422.         if (result)
  423.                 removeItemAt(index);
  424.  
  425.         return result;
  426.     }
  427.    
  428.     /**
  429.      *  Remove the item at the specified index and return it.  
  430.      *  Any items that were after this index are now one index earlier.
  431.      *
  432.      *  @param index the index from which to remove the item
  433.      *  @return the item that was removed
  434.      *  @throws RangeError is index < 0 or index >= length
  435.      *  
  436.      *  @langversion 3.0
  437.      *  @playerversion Flash 9
  438.      *  @playerversion AIR 1.1
  439.      *  @productversion Flex 3
  440.      */
  441.     public function removeItemAt(index:int):Object
  442.     {
  443.         if (index < 0 || index >= length)
  444.                 {
  445.                         var message:String = resourceManager.getString(
  446.                                 "collections", "outOfBounds", [ index ]);
  447.                 throw new RangeError(message);
  448.                 }
  449.  
  450.         var removed:Object = source.splice(index, 1)[0];
  451.         stopTrackUpdates(removed);
  452.         internalDispatchEvent(CollectionEventKind.REMOVE, removed, index);
  453.         return removed;
  454.     }
  455.    
  456.     /**
  457.      *  Remove all items from the list.
  458.      *  
  459.      *  @langversion 3.0
  460.      *  @playerversion Flash 9
  461.      *  @playerversion AIR 1.1
  462.      *  @productversion Flex 3
  463.      */
  464.     public function removeAll():void
  465.     {
  466.         if (length > 0)
  467.         {
  468.             var len:int = length;
  469.             for (var i:int = 0; i < len; i++)
  470.             {
  471.                 stopTrackUpdates(source[i]);
  472.             }
  473.  
  474.             source.splice(0, length);
  475.                         internalDispatchEvent(CollectionEventKind.RESET);
  476.         }    
  477.     }
  478.    
  479.     /**
  480.      *  Notify the view that an item has been updated.  
  481.      *  This is useful if the contents of the view do not implement
  482.      *  <code>IEventDispatcher</code>.  
  483.      *  If a property is specified the view may be able to optimize its
  484.      *  notification mechanism.
  485.      *  Otherwise it may choose to simply refresh the whole view.
  486.      *
  487.      *  @param item The item within the view that was updated.
  488.          *
  489.      *  @param property A String, QName, or int
  490.          *  specifying the property that was updated.
  491.          *
  492.      *  @param oldValue The old value of that property.
  493.          *  (If property was null, this can be the old value of the item.)
  494.          *
  495.      *  @param newValue The new value of that property.
  496.          *  (If property was null, there's no need to specify this
  497.          *  as the item is assumed to be the new value.)
  498.      *
  499.      *  @see mx.events.CollectionEvent
  500.      *  @see mx.core.IPropertyChangeNotifier
  501.      *  @see mx.events.PropertyChangeEvent
  502.      *  
  503.      *  @langversion 3.0
  504.      *  @playerversion Flash 9
  505.      *  @playerversion AIR 1.1
  506.      *  @productversion Flex 3
  507.      */
  508.      public function itemUpdated(item:Object, property:Object = null,
  509.                                  oldValue:Object = null,
  510.                                  newValue:Object = null):void
  511.     {
  512.         var event:PropertyChangeEvent =
  513.                         new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE);
  514.        
  515.                 event.kind = PropertyChangeEventKind.UPDATE;
  516.         event.source = item;
  517.         event.property = property;
  518.         event.oldValue = oldValue;
  519.         event.newValue = newValue;
  520.        
  521.                 itemUpdateHandler(event);        
  522.     }    
  523.    
  524.     /**
  525.      *  Return an Array that is populated in the same order as the IList
  526.      *  implementation.  
  527.      *
  528.      *  @throws ItemPendingError if the data is not yet completely loaded
  529.      *  from a remote location
  530.      *  
  531.      *  @langversion 3.0
  532.      *  @playerversion Flash 9
  533.      *  @playerversion AIR 1.1
  534.      *  @productversion Flex 3
  535.      */
  536.     public function toArray():Array
  537.     {
  538.         return source.concat();
  539.     }
  540.    
  541.     /**
  542.      *  Ensures that only the source property is seralized.
  543.      *  @private
  544.      */
  545.     public function readExternal(input:IDataInput):void
  546.     {
  547.         source = input.readObject();
  548.     }
  549.    
  550.     /**
  551.      *  Ensures that only the source property is serialized.
  552.      *  @private
  553.      */
  554.     public function writeExternal(output:IDataOutput):void
  555.     {
  556.         output.writeObject(_source);
  557.     }
  558.  
  559.         /**
  560.      *  Pretty prints the contents of this ArrayList to a string and returns it.
  561.      *  
  562.      *  @langversion 3.0
  563.      *  @playerversion Flash 9
  564.      *  @playerversion AIR 1.1
  565.      *  @productversion Flex 3
  566.      */
  567.     override public function toString():String
  568.         {
  569.                 if (source)
  570.                         return source.toString();
  571.                 else
  572.                         return getQualifiedClassName(this);    
  573.         }      
  574.    
  575.     //--------------------------------------------------------------------------
  576.     //
  577.     // Internal Methods
  578.     //
  579.     //--------------------------------------------------------------------------
  580.  
  581.         /**
  582.          *  Enables event dispatch for this list.
  583.          *  
  584.          *  @langversion 3.0
  585.          *  @playerversion Flash 9
  586.          *  @playerversion AIR 1.1
  587.          *  @productversion Flex 3
  588.          */
  589.         private function enableEvents():void
  590.         {
  591.                 _dispatchEvents++;
  592.                 if (_dispatchEvents > 0)
  593.                         _dispatchEvents = 0;
  594.         }
  595.        
  596.         /**
  597.          *  Disables event dispatch for this list.
  598.          *  To re-enable events call enableEvents(), enableEvents() must be called
  599.          *  a matching number of times as disableEvents().
  600.          *  
  601.          *  @langversion 3.0
  602.          *  @playerversion Flash 9
  603.          *  @playerversion AIR 1.1
  604.          *  @productversion Flex 3
  605.          */
  606.         private function disableEvents():void
  607.         {
  608.                 _dispatchEvents--;
  609.         }
  610.        
  611.         /**
  612.          *  Dispatches a collection event with the specified information.
  613.          *
  614.          *  @param kind String indicates what the kind property of the event should be
  615.          *  @param item Object reference to the item that was added or removed
  616.          *  @param location int indicating where in the source the item was added.
  617.          *  
  618.          *  @langversion 3.0
  619.          *  @playerversion Flash 9
  620.          *  @playerversion AIR 1.1
  621.          *  @productversion Flex 3
  622.          */
  623.         private function internalDispatchEvent(kind:String, item:Object = null, location:int = -1):void
  624.         {
  625.         if (_dispatchEvents == 0)
  626.         {
  627.                 if (hasEventListener(CollectionEvent.COLLECTION_CHANGE))
  628.                 {
  629.                         var event:CollectionEvent =
  630.                                         new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
  631.                         event.kind = kind;
  632.                         event.items.push(item);
  633.                         event.location = location;
  634.                         dispatchEvent(event);
  635.                     }
  636.  
  637.                 // now dispatch a complementary PropertyChangeEvent
  638.                 if (hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE) &&
  639.                    (kind == CollectionEventKind.ADD || kind == CollectionEventKind.REMOVE))
  640.                 {
  641.                         var objEvent:PropertyChangeEvent =
  642.                                         new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE);
  643.                         objEvent.property = location;
  644.                         if (kind == CollectionEventKind.ADD)
  645.                                 objEvent.newValue = item;
  646.                         else
  647.                                 objEvent.oldValue = item;
  648.                         dispatchEvent(objEvent);
  649.                 }
  650.             }
  651.         }
  652.        
  653.     /**
  654.      *  Called whenever any of the contained items in the list fire an
  655.      *  ObjectChange event.  
  656.      *  Wraps it in a CollectionEventKind.UPDATE.
  657.      *  
  658.      *  @langversion 3.0
  659.      *  @playerversion Flash 9
  660.      *  @playerversion AIR 1.1
  661.      *  @productversion Flex 3
  662.      */    
  663.     protected function itemUpdateHandler(event:PropertyChangeEvent):void
  664.     {
  665.                 internalDispatchEvent(CollectionEventKind.UPDATE, event);
  666.                 // need to dispatch object event now
  667.         if (_dispatchEvents == 0 && hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE))
  668.         {
  669.                 var objEvent:PropertyChangeEvent = PropertyChangeEvent(event.clone());
  670.                 var index:uint = getItemIndex(event.target);
  671.                 objEvent.property = index.toString() + "." + event.property;
  672.                 dispatchEvent(objEvent);
  673.         }
  674.     }
  675.    
  676.     /**
  677.      *  If the item is an IEventDispatcher watch it for updates.  
  678.      *  This is called by addItemAt and when the source is initially
  679.      *  assigned.
  680.      *  
  681.      *  @langversion 3.0
  682.      *  @playerversion Flash 9
  683.      *  @playerversion AIR 1.1
  684.      *  @productversion Flex 3
  685.      */
  686.     protected function startTrackUpdates(item:Object):void
  687.     {
  688.         if (item && (item is IEventDispatcher))
  689.         {
  690.             IEventDispatcher(item).addEventListener(
  691.                                                         PropertyChangeEvent.PROPERTY_CHANGE,
  692.                                         itemUpdateHandler, false, 0, true);
  693.         }
  694.     }
  695.    
  696.     /**
  697.      *  If the item is an IEventDispatcher stop watching it for updates.
  698.      *  This is called by removeItemAt, removeAll, and before a new
  699.      *  source is assigned.
  700.      *  
  701.      *  @langversion 3.0
  702.      *  @playerversion Flash 9
  703.      *  @playerversion AIR 1.1
  704.      *  @productversion Flex 3
  705.      */
  706.     protected function stopTrackUpdates(item:Object):void
  707.     {
  708.         if (item && item is IEventDispatcher)
  709.         {
  710.             IEventDispatcher(item).removeEventListener(
  711.                                                         PropertyChangeEvent.PROPERTY_CHANGE,
  712.                                         itemUpdateHandler);    
  713.         }
  714.     }
  715.    
  716.     //--------------------------------------------------------------------------
  717.     //
  718.     // Variables
  719.     //
  720.     //--------------------------------------------------------------------------
  721.  
  722.         /**
  723.          *  indicates if events should be dispatched.
  724.          *  calls to enableEvents() and disableEvents() effect the value when == 0
  725.          *  events should be dispatched.
  726.          *  
  727.          *  @langversion 3.0
  728.          *  @playerversion Flash 9
  729.          *  @playerversion AIR 1.1
  730.          *  @productversion Flex 3
  731.          */
  732.         private var _dispatchEvents:int = 0;
  733.     private var _source:Array;
  734.     private var _uid:String;
  735. }
  736.  
  737. }