Adobe Flex 3 Help

Using drag-and-drop with list-based controls

The following controls include built-in support for the drag-and-drop operation:

The built-in support for these controls lets you move items by dragging them from a drag-enabled control to a drop-enabled control. However, to copy items, you must add additional logic. For more information, see Moving and copying data.

The following drag-and-drop example lets you move items from one List control to another:

<?xml version="1.0"?>
<!-- dragdrop\SimpleListToListMove.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
    creationComplete="initApp();">
    
    <mx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;

            private function initApp():void {
                srclist.dataProvider = 
                    new ArrayCollection(['Reading', 'Television', 'Movies']);
                destlist.dataProvider = new ArrayCollection([]);
            }
        ]]>
    </mx:Script>

    <mx:HBox>
        <mx:VBox>
            <mx:Label text="Available Activities"/>
            <mx:List id="srclist" 
                allowMultipleSelection="true"
                dragEnabled="true"
                dragMoveEnabled="true"/>
        </mx:VBox>

        <mx:VBox>
            <mx:Label text="Activities I Like"/>
            <mx:List id="destlist" 
                dropEnabled="true"/>
        </mx:VBox>
    </mx:HBox>

    <mx:Button id="b1" 
        label="Reset"
        click="initApp()"
    />

</mx:Application>

The executing SWF file for the previous example is shown below:

By setting the dragEnabled property to true on the first List and the dropEnabled property to true on the second List control, you enabled users to drag items from the first list to the second without worrying about any of the underlying event processing.

For all list classes except the Tree control, the default value of the dragMoveEnabled property is false, so you can only copy elements from one control to the other. By setting the dragMoveEnabled to true in the first List control, you can move and copy data. For the Tree control, the default value of the dragMoveEnabled property is true.

When the dragMoveEnabled property is set to true, the default drag-and-drop action is to move the drag data. To perform a copy, hold down the Control key during the drag-and-drop operation.

The only requirement on the drag and drop operation is that the structure of the data providers must match for the two controls. In this example, the data provider for srclist is an Array of Strings, and the data provider for the destination List control is an empty Array. If the data provider for destlist is an Array of some other type of data, destlist might not display the dragged data correctly.

You can modify the dragged data as part of a drag-and-drop operation to make the dragged data compatible with the destination. For an example of dragging data from one control to another when the data formats do not match, see Example: Copying data from a List control to a DataGrid control.

You can allow two-way drag and drop by setting the dragEnabled, dropEnabled, and dragMoveEnabled properties to true for both list-based controls, as the following example shows for two DataGrid controls. In this example, you can drag and drop rows from either DataGrid control to the other:

<?xml version="1.0"?>
<!-- dragdrop\SimpleDGToDG.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
    creationComplete="initApp();">

    <mx:Script>
      <![CDATA[
          import mx.collections.ArrayCollection;
      
          private function initApp():void {
            srcgrid.dataProvider = new ArrayCollection([
              {Artist:'Carole King', Album:'Tapestry', Price:11.99},
              {Artist:'Paul Simon', Album:'Graceland', Price:10.99},
              {Artist:'Original Cast', Album:'Camelot', Price:12.99},
              {Artist:'The Beatles', Album:'The White Album', Price:11.99}
            ]);

            destgrid.dataProvider = new ArrayCollection([]);    
          }
      ]]>
    </mx:Script>

    <mx:HBox>
        <mx:VBox>
            <mx:Label text="Available Albums"/>
            <mx:DataGrid id="srcgrid" 
                allowMultipleSelection="true" 
                dragEnabled="true" 
                dropEnabled="true" 
                dragMoveEnabled="true">
                <mx:columns>
                    <mx:DataGridColumn dataField="Artist"/>
                    <mx:DataGridColumn dataField="Album"/>
                    <mx:DataGridColumn dataField="Price"/>
                </mx:columns>    
            </mx:DataGrid>
        </mx:VBox>

        <mx:VBox>
            <mx:Label text="Buy These Albums"/>
            <mx:DataGrid id="destgrid" 
                allowMultipleSelection="true" 
                dragEnabled="true" 
                dropEnabled="true" 
                dragMoveEnabled="true">
                <mx:columns>
                    <mx:DataGridColumn dataField="Artist"/>
                    <mx:DataGridColumn dataField="Album"/>
                    <mx:DataGridColumn dataField="Price"/>
                </mx:columns>    
            </mx:DataGrid>
        </mx:VBox>
    </mx:HBox>

    <mx:Button id="b1" 
        label="Reset"
        click="initApp()"
    />

</mx:Application>

The executing SWF file for the previous example is shown below:

Dragging and dropping in the same control

One use of drag and drop is to let you reorganize the items in a list-based control by dragging the items and then dropping them in the same control. In the next example, you define a Tree control, and let the user reorganize the nodes of the Tree control by dragging and dropping them. In this example, you set the dragEnabled and dropEnabled to true for the Tree control (the dragMoveEnabled property defaults to true for the Tree control):

<?xml version="1.0"?>
<!-- dragdrop\SimpleTreeSelf.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

    <mx:Script>
        <![CDATA[
            // Initialize the data provider for the Tree.
            private function initApp():void {
                firstList.dataProvider = treeDP;
            }
        ]]>
    </mx:Script>
    
    <mx:XML id="treeDP">
        <node label="Mail">
            <node label="Inbox"/>
            <node label="Personal Folder">
                <node label="Demo"/>
                <node label="Personal"/>
                <node label="Saved Mail"/>
                <node label="bar"/>
            </node>
            <node label="Calendar"/>
            <node label="Sent"/>
            <node label="Trash"/>
        </node>
    </mx:XML>

    <mx:Tree id="firstList" 
        showRoot="false"
        labelField="@label"
        dragEnabled="true" 
        dropEnabled="true" 
        allowMultipleSelection="true"
        creationComplete="initApp();"/>

</mx:Application>

The executing SWF file for the previous example is shown below:

Drag and drop properties for list-based controls

List-based controls provide properties and methods for managing the drag-and-drop operation. The following table lists these properties and methods:

Property/Method

Description

dropIndicatorSkin

Specifies the name of the skin to use for the drop-insert indicator which shows where the dragged data will be inserted.

The default value is ListDropIndicator.

dragEnabled

A Boolean value that specifies whether the control is a drag initiator. The default value is false. When true, users can drag selected items from the control. When a user drags items from the control, Flex creates a DragSource object that contains the following data objects:

  • A copy of the selected item or items in the control.
    For all controls except for Tree, the format string is "items" and the items implement the IDataProvider interface.
    For Tree controls the format string is "treeItems" and the items implement the ITreeDataProvider API interface.
  • A copy of the initiator, with a format String of "source".
dropEnabled

A Boolean value that specifies whether the control can be a drop target that uses default values for handling items dropped onto it. The default value is false, which means that you must write event handlers for the drag events. When the value is true, you can drop items onto the control by using the default drop behavior.

When you set dropEnabled to true, Flex automatically calls the showDropFeedback() and hideDropFeedback() methods to display the drop indicator.

dragMoveEnabled

If the value is true, and the dragEnabled property is true, specifies that you can move or copy items from the drag initiator to the drop target. When you move an item, the item is deleted from the drag initiator when you add it to the drop target.

If the value is false, you can only copy an item to the drop target. For a copy, the item in the drag initiator is not affected by the drop.

When the dragMoveEnabled property is true, you must hold down the Control key during the drop operation to perform a copy.

The default value is false for all list controls except the Tree control, and true for the Tree control.

calculateDropIndex

Returns the item index in the drop target where the item will be dropped. Used by the dragDrop event handler to add the items in the correct location.

Not available in the TileList or HorizontalList controls.

hideDropFeedback()

Hides drop target feedback and removes the focus rectangle from the target. You typically call this method from within the handler for the dragExit and dragDrop events.

showDropFeedback()

Specifies to display the focus rectangle around the target control and positions the drop indicator where the drop operation should occur. If the control has active scroll bars, hovering the mouse pointer over the control's top or bottom scrolls the contents.

You typically call this method from within the handler for the dragOver event.

Maintaining type information during a copy

When you use the built-in support of the list-based controls to copy data from one list-based control to another list-based control, you might run into an occasion where you lose the data-type information of the copied data. The loss of data-type information can occur when:

  • You perform a copy operation between two list-based controls; it does not occur during a move operation
  • The data type of the copied item is not a basic ActionScript data type, such as Date, Number, Object, or String
  • The data type of the copied item is not DisplayObject, or a subclass of DisplayObject

For example, you define the following class, Car.as, that you use to populate the data provider of a List control:

package
{
    // dragdrop/Car.as
    
    [RemoteClass]
    public class Car extends Object
    {
        // Constructor.
        public function Car()
        {
            super();
        }
        
        // Class properties.
        public var numWheels:int;
        public var model:String;
        public var make:String;
        
        public function get label():String
        {
            return make + " " + model;
        }        
    }
}

Notice that the Car.as file includes the [RemoteClass] metadata tag. This metadata tag is required to register the Car data type with Flex so that its type information is preserved during the copy operation. If you omit the [RemoteClass] metadata tag, type information is lost.

You then use that class in your application, as the following example shows:

<?xml version="1.0"?>
<!-- dragdrop\DandDRemoteClassListUpdated.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
    layout="absolute" xmlns="*">

    <mx:Script>
        <![CDATA[
        
            public function changeit():void
            {
                if (list2.dataProvider != null)
                {                
                    msg.text += list2.dataProvider[0]
                    
                    if(list2.dataProvider[0] is Car)
                        msg.text += " Is Car\n";
                    else
                        msg.text += " Is NOT Car\n";
                }
            }
        ]]>
    </mx:Script>

    <mx:List id="list1" 
        x="10" y="45" 
        width="160" height="120" 
        dragEnabled="true" 
        dragMoveEnabled="true">
        <mx:dataProvider>
            <mx:Array>
                <Car model="Camry" make="Toyota" numWheels="4"/>
                <Car model="Prius" make="Toyota" numWheels="4"/>
            </mx:Array>
       </mx:dataProvider>
    </mx:List>

    <mx:List  id="list2"
        x="200" y="45" 
        width="160" height="120" 
        dropEnabled="true"/>
    
    <mx:Button label="Access it as button" click="changeit();"/>
    
    <mx:TextArea id="msg"  
        x="10" y="200"
        width="400" height="100"/>
</mx:Application>

The executing SWF file for the previous example is shown below: