apache-flexadvanceddatagrid

Advanced Data Grid: Error: Bookmark no longer valid


I am working on an indent and outdent for the advanced datagrid. I have a set of functions which work when operating on the underlying data fine, but which throw "Error: Bookmark no longer valid" when operating on the selected items of the datagrid.

When I run this code it runs fine:

indentLeaf(l5)
outdentLeaf(l4)

But this code fails:

adg.selectedItem = l5
indentLeaf(adg.selectedItem as Leaf)
adg.selectedItem = l4
outdentLeaf(adg.selectedItem as Leaf)

The code does not fail in all instances, only for some configurations of the data grid data tree.

The code needs to be run in the debugger version of the flash player if you want to see the error thrown. I have cut and pasted the error I get into the text area for reference as well as below.

The code in the toy app seems to recover ok when the exception is thrown, but in my larger app it leads to hard crashes.

Example code can be found here with view source turned on: http://www.crcarlson.com/adg/ADGArrayCollectionUpdate.swf

To create the error, reset the tree and then click "indent/outdent2"

I would appreciate any suggestions on how to get around this.

The full stack trace looks like this:

Error: Bookmark no longer valid.
at ListCollectionViewCursor/seek()[E:\dev\4.x\frameworks\projects\framework\src\mx\collections\ListCollectionView.as:2417]
at mx.collections::HierarchicalCollectionViewCursor/get current()[E:\dev\4.x\frameworks\projects\datavisualization\src\mx\collections\HierarchicalCollectionViewCursor.as:220]
at mx.collections::HierarchicalCollectionViewCursor/collectionChangeHandler()[E:\dev\4.x\frameworks\projects\datavisualization\src\mx\collections\HierarchicalCollectionViewCursor.as:1143]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.collections::HierarchicalCollectionView/nestedCollectionChangeHandler()[E:\dev\4.x\frameworks\projects\datavisualization\src\mx\collections\HierarchicalCollectionView.as:1595]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.collections::ListCollectionView/dispatchEvent()[E:\dev\4.x\frameworks\projects\framework\src\mx\collections\ListCollectionView.as:1024]
at mx.collections::ListCollectionView/handlePropertyChangeEvents()[E:\dev\4.x\frameworks\projects\framework\src\mx\collections\ListCollectionView.as:1433]
at mx.collections::ListCollectionView/listChangeHandler()[E:\dev\4.x\frameworks\projects\framework\src\mx\collections\ListCollectionView.as:1300]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.collections::ArrayList/internalDispatchEvent()[E:\dev\4.x\frameworks\projects\framework\src\mx\collections\ArrayList.as:673]
at mx.collections::ArrayList/itemUpdateHandler()[E:\dev\4.x\frameworks\projects\framework\src\mx\collections\ArrayList.as:704]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at Leaf/dispatchChildrenChanged()[C:\adobeFlexTraining\_workspace\ADGArrayCollectionUpdate\src\Leaf.as:119]
at Leaf/addChildAt()[C:\adobeFlexTraining\_workspace\ADGArrayCollectionUpdate\src\Leaf.as:63]
at Leaf/move()[C:\adobeFlexTraining\_workspace\ADGArrayCollectionUpdate\src\Leaf.as:96]
at ADGArrayCollectionUpdate/outdentLeaf()[C:\adobeFlexTraining\_workspace\ADGArrayCollectionUpdate\src\ADGArrayCollectionUpdate.mxml:86]
at ADGArrayCollectionUpdate/IO2_clickHandler()[C:\adobeFlexTraining\_workspace\ADGArrayCollectionUpdate\src\ADGArrayCollectionUpdate.mxml:113]
at ADGArrayCollectionUpdate/__IO2_click()[C:\adobeFlexTraining\_workspace\ADGArrayCollectionUpdate\src\ADGArrayCollectionUpdate.mxml:183]

Solution

  • I just found a workaround for this bug (I am using SDK 3.5 but I guess a 4.1 fix would be very much the same). The problem lies within the "current()" getter of the HierarchicalCollectionViewCursor class.

    It doesn't catch the CursorError that's caused by an invalid bookmark.

    Step 1 is to create a better cursor class:

    public class HierarchicalCollectionViewCursor2 extends HierarchicalCollectionViewCursor
    {
        public function HierarchicalCollectionViewCursor2(collection:HierarchicalCollectionView, model:ICollectionView, hierarchicalData:IHierarchicalData)
        {
            super(collection, model, hierarchicalData);
        }
    
    
        override public function get current() : Object
        {
            // original HierarchicalCollectionViewCursor class fails to catch the "bookmark no
            // longer valid" Error, which is thrown as a CollectionViewError instance in ListCollectionView,
            // but transformed to a CursorError within the same class
            try {
                var result:Object = super.current;
            }
            catch (e:CursorError) {
                result = null;
            }
    
            // done
            return result;
        }
    }
    

    Step 2 is to create a HierarchicalCollectionView class, which returns that new cursor:

    use namespace mx_internal;
    
    public class HierarchicalCollectionView2 extends HierarchicalCollectionView
    {
        public function HierarchicalCollectionView2(hierarchicalData:IHierarchicalData=null, argOpenNodes:Object=null)
        {
            super(hierarchicalData, argOpenNodes);
        }
    
    
        override public function createCursor() : IViewCursor
        {
            return new HierarchicalCollectionViewCursor2(this, treeData, this.source);
        }
    }
    

    Step 3 is to actually use that new HierarchicalCollectionView2 class as your data-provider.

    var itemsAC:ArrayCollection = new ArrayCollection();
    // add items etc
    this.adgDataProvider = new HierarchicalCollectionView2(new HierarchicalData(itemsAC));
    

    Now you would think that all is well BUT the drama wouldn't be complete without another annoying Flex-SDK bug. In this case its:

    https://bugs.adobe.com/jira/browse/FLEXDMV-1846

    So, Step 4 is to subclass the AdvancedDataGrid component as described in the bug issue.

    That's it -- works for me!