Dragging from a Tree to a List/TileList

In the Flex framework, we have made dragging and dropping within various List components fairly trivial. Assuming that your data is similar, you simply need to add dragEnabled=true to your source and then dropEnabled=false for your destination. However, the one exception in this case is Tree. By default, you cannot drag any items from any other drag enabled List component (other than another tree). If you look at the source of the framework, you will see that all of the event handlers used for TileList, List, HorizontalList and DataGrid are in ListBase.as. However, Tree has its own custom drag event handlers. Therefore, if you want to share data between another List component and a Tree using drag and drop, you will need to override all of the drag event handlers. These handlers include dragEnter, dragDrop, dragComplete and dragOver. Here is an example Application where you can drag items from a Tree to a TileList. The items will be removed from the Tree.

Here is the code for the Tree and TileList:

<mx:TileList id=”srcTileList” dropEnabled=”true” dragOver=”doDragOver(event)”
dragEnter=”doDragEnter(event)”dragDrop=”doDragDrop(event)” columnWidth=”100″ /><mx:Tree id=”destTree” dragEnabled=”true” labelField=”@label” showRoot=”false” dragComplete=”doDragComplete(event)” width=”250″ />

And here are my event handlers for each drag events:

public function doDragOver(event:DragEvent) : void
{
event.preventDefault();DragManager.showFeedback(event.ctrlKey ? DragManager.COPY : DragManager.MOVE);
TileList(event.target).showDropFeedback(event);
}public function doDragEnter(event:DragEvent): void
{
event.preventDefault();DragManager.acceptDragDrop(TileList(event.target));
DragManager.showFeedback(event.ctrlKey ? DragManager.COPY : DragManager.MOVE);
TileList(event.target).showDropFeedback(event);
}public function doDragDrop(event:DragEvent): void
{
event.preventDefault();
var myTileList:TileList = TileList(event.target);
myTileList.hideDropFeedback(event);if (event.dragSource.hasFormat(“treeItems”))
{
if (!myTileList.dataProvider)
// Create an empty collection to drop items into.
myTileList.dataProvider = [];

var items:Array = event.dragSource.dataForFormat(“treeItems”) as Array;
for (var i:int = items.length – 1; i >= 0; i–)
{
myTileList.dataProvider.addItemAt(String(items[i].@label), TileList(event.target).calculateDropIndex(event));
}
}
}

public function doDragComplete(event:DragEvent): void
{
event.preventDefault();
if (event.action == DragManager.MOVE && Tree(event.target).dragMoveEnabled)
{
var target:Tree = Tree(event.target)
if (event.relatedObject != this)
{
//if we dropped on another component
//then we need to remove from ourself first
var items:Array = event.dragSource.dataForFormat(“treeItems”) as Array;
var parent:*;
var index:int;

//do the remove
for (var i:int=0; i<items.length; i++)
{
parent = target.getParentItem(items[i]);
index = getChildIndexInParent(parent, items[i], target);
target.mx_internal::removeChildItem(parent, items[i], index);
}
}
}
}

private function getChildIndexInParent(parent:Object, child:Object, target:Tree):int
{
var index:int = 0;
if (!parent)
{
var cursor:IViewCursor = ICollectionView(target.dataProvider).createCursor();
while (!cursor.afterLast)
{
if (child === cursor.current)
break;
index++;
cursor.moveNext();
}
}
else
{
if (parent != null && target.dataDescriptor.isBranch(parent) &&
target.dataDescriptor.hasChildren(parent))
{
var children:ICollectionView = target.dataDescriptor.getChildren(parent);
if (children.contains(child))
{
for (; index < children.length; index++)
{
if (child === children[index])
break;
}
}
}
}
return index;
}

Demo: TileList2Tree.swf
Source code: TileList2Tree.mxml

5 responses

  1. Thank you for this post. I have been banging my head against my desk trying to get this to work, and did not realize Tree has it’s own custom drag event handlers that have to be overridden.

    I’m back in business! Thanks again!

  2. What if I want to NOT have the items removed from the tree? I have tried to prevent the default behavior and do a DragManager.COPY call but it still MOVEs it out of the list.

  3. Excellent post, thanks! I was struggling with getting this to work, saved me much time! 🙂

  4. Great Post…..I was trying to make it work..and could nt figure it y….Thanks,

  5. Thanks, my day just got better 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: