You implement a move and a copy as part of a drag-and-drop operation.
When you move data, you add it to the drop target and delete it from the drag initiator. You use the dragDrop event for the drop target to add the data, and the dragComplete event for the drag initiator to remove the data.
How much work you have to do to implement the move depends on whether the drag initiator and drop target are list-based controls or nonlist-based controls:
list
based
control
You do not have to do any additional work; list-based controls handle all of the processing required to move data from one list-based control to another list-based control. For an example, see Performing a drag and drop.
nonlist-based control
If the drag initiator is a nonlist-based control, you have to implement the event handler for the dragComplete event to delete the drag data from the drag initiator. If the drop target is a nonlist-based control, you have to implement the event handler for the dragDrop event to add the data to the drop target. For an example, see Example: Moving and copying data for a nonlist-based control.
The list-based controls can automate all of the drag-and-drop operation except for when you copy the drag data to the drop target, rather than move it. If you want to copy data when using a list-based control as the drop target, you must explicitly handle the dragDrop event for the drop target.
When using a nonlist-based control as the drop target, you always have to write an event handler for the dragDrop event, regardless of whether you are performing a move or copy.
Copying data in an object-oriented environment is not a trivial task. An object may contain pointers to other objects that themselves contain pointers to even more objects. Rather than try to define a universal object copy as part of the drag-and-drop operation, Flex leaves it to you to implement object copying because you will have first-hand knowledge of your data format and requirements.
In some circumstances, you may have objects that implement a clone method that makes it easy to create a byte copy of the object. In other cases, you will have to perform the copy yourself by copying individual fields of the source object to the destination object.
The following example lets you copy items from one List control to another. In this example, even though you set the dropEnabled property to true in the drop target, you still write an event handler for the dragDrop event. The event handler calls Event.preventDefualt() to explicitly prohibit the default event handler from executing. The reason to set the dropEnabled property to true in the drop target is so that Flex automatically handles all of the other events (dragEnter, dragOver, and dragExit) on the drop target.
The default value of the dragMoveEnabled property is false, so that you can only copy elements from one List control to the other. If you modify the example to set dragMoveEnabled to true in the drag initiator, you can move and copy elements. To copy a list element, hold down the Control key during the drag-and-drop operation:
<?xml version="1.0"?>
<!-- dragdrop\DandDListToListCopy.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp();">
<mx:Script>
<![CDATA[
import mx.events.DragEvent;
import mx.managers.DragManager;
import mx.core.DragSource;
import mx.collections.IList;
import mx.collections.ArrayCollection;
private function initApp():void {
firstList.dataProvider = new ArrayCollection([
{label:"First", data:"1"},
{label:"Second", data:"2"},
{label:"Third", data:"3"},
{label:"Fourth", data:"4"},
]);
secondList.dataProvider = new ArrayCollection([]);
}
private function dragDropHandler(event:DragEvent):void {
if (event.dragSource.hasFormat("items"))
{
// Explicitly handle the dragDrop event.
event.preventDefault();
// Since you are explicitly handling the dragDrop event,
// call hideDropFeedback(event) to have the drop target
// hide the drop indicator.
// The drop indicator is created
// automatically for the list controls by the built-in
// event handler for the dragOver event.
event.currentTarget.hideDropFeedback(event);
// Get drop target.
var dropTarget:List=List(event.currentTarget);
// Get the dragged item from the drag initiator.
// The List control always writes an Array
// to the dragSource object,
// even if there is only one item being dragged.
var itemsArray:Array =
event.dragSource.dataForFormat("items") as Array;
// Copy the dragged data into a new Object.
var tempItem:Object =
{label: itemsArray[0].label, data: itemsArray[0].data};
// Get the drop location in the destination.
var dropLoc:int = dropTarget.calculateDropIndex(event);
// Add the new object to the drop target.
IList(dropTarget.dataProvider).addItemAt(tempItem, dropLoc);
}
}
]]>
</mx:Script>
<mx:HBox>
<mx:List id="firstList"
dragEnabled="true"/>
<mx:List id="secondList"
dropEnabled="true"
dragDrop="dragDropHandler(event);"/>
</mx:HBox>
<mx:Button id="b1"
label="Reset"
click="initApp()"
/>
</mx:Application>
The executing SWF file for the previous example is shown below:
To perform the copy, the event handler creates a new Object, then copies the individual data fields of the drag data into the new Object. Then, the event handler adds the new Object to the drop target's data provider.
Unlike the example in the section Example: Moving and copying data for a nonlist-based control, you do not have to write the dragOver or dragComplete event handlers. While Flex cannot perform the copy, Flex does recognize when you perform a copy or a move, and automatically removes the data from the drag initiator for you on a move.
You can use drag and drop to copy data between two different types of controls, or between controls that use different data formats. To handle this situation, you write an event handler for the dragDrop event that converts the data from the format of the drag initiator to the format required by the drop target.
In the following example, you can move or copy data from a List control to a DataGrid control. The event handler for the dragDrop event adds a new field to the dragged data that contains the date:
<?xml version="1.0"?>
<!-- dragdrop\DandDListToDG.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp();">
<mx:Script>
<![CDATA[
import mx.events.DragEvent;
import mx.managers.DragManager;
import mx.core.DragSource;
import mx.collections.IList;
import mx.collections.ArrayCollection;
private function initApp():void {
srcList.dataProvider = new ArrayCollection([
{label:"First", data:"1"},
{label:"Second", data:"2"},
{label:"Third", data:"3"},
{label:"Fourth", data:"4"},
]);
destDG.dataProvider = new ArrayCollection([]);
}
private function dragDropHandler(event:DragEvent):void {
if (event.dragSource.hasFormat("items"))
{
// Explicitly handle the dragDrop event.
event.preventDefault();
// Since you are explicitly handling the dragDrop event,
// call hideDropFeedback(event) to have the drop target
// hide the drop indicator.
// The drop indicator is created
// automatically for the list controls by the built-in
// event handler for the dragOver event.
event.currentTarget.hideDropFeedback(event);
// Get drop target.
var dropTarget:DataGrid =
DataGrid(event.currentTarget);
var itemsArray:Array =
event.dragSource.dataForFormat('items') as Array;
var tempItem:Object =
{ label: itemsArray[0].label,
data: itemsArray[0].data,
date: new Date()
};
// Get the drop location in the destination.
var dropLoc:int = dropTarget.calculateDropIndex(event);
IList(dropTarget.dataProvider).addItemAt(tempItem, dropLoc);
}
}
]]>
</mx:Script>
<mx:HBox>
<mx:List id="srcList"
dragEnabled="true"
dragMoveEnabled="true"/>
<mx:DataGrid id="destDG"
dropEnabled="true"
dragDrop="dragDropHandler(event);">
<mx:columns>
<mx:DataGridColumn dataField="label"/>
<mx:DataGridColumn dataField="data"/>
<mx:DataGridColumn dataField="date"/>
</mx:columns>
</mx:DataGrid>
</mx:HBox>
<mx:Button id="b1"
label="Reset"
click="initApp()"
/>
</mx:Application>
The executing SWF file for the previous example is shown below:
The dragComplete event occurs on the drag initiator when a drag operation completes, either when the drag data drops onto a drop target, or when the drag-and-drop operation ends without performing a drop operation. The drag initiator can specify a handler to perform cleanup actions when the drag finishes, or when the target does not accept the drop.
One use of the dragComplete event handler is to remove from the drag initiator the objects that you move to the drop target. The items that you drag from a control are copies of the original items, not the items themselves. Therefore, when you drop items onto the drop target, you use the dragComplete event handler to delete them from the drag initiator.
To determine the type of drag operation (copy or move), you use the action property of the event object passed to the event handler. This method returns the drag feedback set by the dragOver event handler. For more information, see Example: Handling the dragOver and dragExit events for the drop target.
In the following example, you drag an Image control from one Canvas container to another. As part of the drag-and-drop operation, you can move the Image control, or copy it by holding down the Control key. If you perform a move, the dragComplete event handler removes the Image control from its original parent container:
<?xml version="1.0"?>
<!-- dragdrop\DandDImageCopyMove.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="horizontal">
<mx:Script>
<![CDATA[
import mx.managers.DragManager;
import mx.core.DragSource;
import mx.events.DragEvent;
import flash.events.MouseEvent;
// Embed icon image.
[Embed(source='assets/globe.jpg')]
public var globeImage:Class;
// The mouseMove event handler for the Image control
// functioning as the drag initiator.
private function mouseOverHandler(event:MouseEvent):void
{
var dragInitiator:Image=Image(event.currentTarget);
var ds:DragSource = new DragSource();
ds.addData(dragInitiator, "img");
// The drag manager uses the image as the drag proxy
// and sets the alpha to 1.0 (opaque),
// so it appears to be dragged across the canvas.
var imageProxy:Image = new Image();
imageProxy.source = globeImage;
imageProxy.height=10;
imageProxy.width=10;
DragManager.doDrag(dragInitiator, ds, event,
imageProxy, -15, -15, 1.00);
}
// The dragEnter event handler for the Canvas container
// functioning as the drop target.
private function dragEnterHandler(event:DragEvent):void {
if (event.dragSource.hasFormat("img"))
DragManager.acceptDragDrop(Canvas(event.currentTarget));
}
// The dragOver event handler for the Canvas container
// sets the type of drag-and-drop
// operation as either copy or move.
// This information is then used in the
// dragComplete event handler for the source Canvas container.
private function dragOverHandler(event:DragEvent):void
{
if (event.dragSource.hasFormat("img")) {
if (event.ctrlKey) {
DragManager.showFeedback(DragManager.COPY);
return;
}
else {
DragManager.showFeedback(DragManager.MOVE);
return;
}
}
DragManager.showFeedback(DragManager.NONE);
}
// The dragDrop event handler for the Canvas container
// sets the Image control's position by
// "dropping" it in its new location.
private function dragDropHandler(event:DragEvent):void {
if (event.dragSource.hasFormat("img")) {
var draggedImage:Image =
event.dragSource.dataForFormat('img') as Image;
var dropCanvas:Canvas = event.currentTarget as Canvas;
// Since this is a copy, create a new object to
// add to the drop target.
var newImage:Image=new Image();
newImage.source = draggedImage.source;
newImage.x = dropCanvas.mouseX;
newImage.y = dropCanvas.mouseY;
dropCanvas.addChild(newImage);
}
}
// The dragComplete event handler for the source Canvas container
// determines if this was a copy or move.
// If a move, remove the dragged image from the Canvas.
private function dragCompleteHandler(event:DragEvent):void {
var draggedImage:Image =
event.dragInitiator as Image;
var dragInitCanvas:Canvas =
event.dragInitiator.parent as Canvas;
if (event.action == DragManager.MOVE)
dragInitCanvas.removeChild(draggedImage);
}
]]>
</mx:Script>
<!-- Canvas holding the Image control that is the drag initiator. -->
<mx:Canvas
width="250" height="500"
borderStyle="solid"
backgroundColor="#DDDDDD">
<!-- The Image control is the drag initiator and the drag proxy. -->
<mx:Image id="myimg"
source="@Embed(source='assets/globe.jpg')"
mouseMove="mouseOverHandler(event);"
dragComplete="dragCompleteHandler(event);"/>
</mx:Canvas>
<!-- This Canvas is the drop target. -->
<mx:Canvas
width="250" height="500"
borderStyle="solid"
backgroundColor="#DDDDDD"
dragEnter="dragEnterHandler(event);"
dragOver="dragOverHandler(event);"
dragDrop="dragDropHandler(event);">
</mx:Canvas>
</mx:Application>
The executing SWF file for the previous example is shown below: