Drag and Drop for UIComponents

Drag and drop is a powerful feature in Flex - but is only implemented 'natively' for a few specialized controls. If you need to drag and drop complex objects, controls or data... have no fear! Five minute tutorials are here.

Chances are you've used the Flex List, or similar controls, and have been fully introduced to the coolness that is Flex drag and drop. I'm guessing that you've come up with or been asked to implement a 'spiffy' feature in your application using drag and drop... that falls outside the examples included in the sdk docs. The following example will allow you to perform drag and drop operations among|between any UIComponent.

Lets say - that you have a series of objects that you would like to move from one place to another.

[ example: drag and drop for uicomponents ]

The DragManager can help - but since we aren't working with List based controls... we are going to have initiate the drag and drop process manually with a mouse down event on the object you want to drag:


private function handleMouseDown( event:MouseEvent ):void
{
  // If we are draggin' and droppin' there is no need to go further!
  if ( _dragDropEnabled == false )
     return;

  // Init parameters for drag drop operation...
  if ( event.currentTarget is IUIComponent )
  {
    // The component you click on will become the candidate for D-N-D
    var dragChild:UIComponent = UIComponent( event.currentTarget );

    // We will need to know the parent|child for the remove and 
    // add child operations - push both into drag source data 
    // for use later.
    var dragSource:DragSource = new DragSource();
    dragSource.addData( dragChild.parent, 'dragParent' );
    dragSource.addData( dragChild, 'dragChild' );

    // Let the drag manager take care of the rest
    DragManager.doDrag( dragInitiator, dragSource, event );
  }
}

Any UIComponent(s) that you want to participate in drag and drop operations should call the above event on a mouseDown. The next step is to make sure that the UIComponent(s) that you want to serve as a drop target need to handle dragEnter events:


private function handleDragEnter( event:DragEvent ):void
{
  if ( event.dragSource.hasFormat('dragChild') && event.dragSource.hasFormat('dragParent') )
  {
    // If the currentTarget isn't a UIComponent - this is going to 
    // fail... if it does - you added the handler to something that 
    // isn't a UIComponent... bad developer - bad!
    if ( event.currentTarget is UIComponent )
    {
      // Needed to give a visual indicator that the drag|drop is good.
      var dropTarget:UIComponent = UIComponent( event.currentTarget );					
    
      // What container are we moving around in?
      //   1. We are in the drag source container
      //   2. We are in the drag target container 					
      var dragSource:UIComponent = event.dragSource.dataForFormat( 'dragParent' ) as UIComponent;
    
      // Where are we?
      if ( dropTarget != dragSource )
      {
        DragManager.acceptDragDrop( dropTarget );
        DragManager.showFeedback( DragManager.COPY );
      }						
  
    }
  }
}

The last step is to handle the dragDrop event:


private function handleDragDrop( event:DragEvent ):void
{			
  // If the currentTarget isn't a UIComponent - this is going to fail... 
  // if it does - you added the handler to something that isn't a 
  // UIComponent... bad developer - bad!
  if ( event.currentTarget is UIComponent )
  {
    // The UIComponent that we *hope* to drop to...
    var dropTarget:UIComponent = UIComponent( event.currentTarget );

    // The UIComponent that we *hope* to drag from..
    var dragSource:UIComponent = event.dragSource.dataForFormat( 'dragParent' ) as UIComponent;

    // If we are still in the 'from' container... then the 'from' and 'to' 
    // container are the same... *bah*
    if ( dropTarget != dragSource )
    {
      // The 'from' and 'to' are different - yay!
      var child:UIComponent = event.dragSource.dataForFormat( 'dragChild' ) as UIComponent;

      // Remove and add operations to transit the child to its new home
      dragSource.removeChild( child );
      dropTarget.addChild( child );	
    }

  }
}

I've stripped down the code listed here a bit - but this should set you on the right path. You can easily take this example and add any additional data and/or objects you require using dragSource.addData(). The source includes comments for feature extension - available either source view or project download.

[ example: drag and drop for uicomponents ]
[ source: drag and drop for uicomponents ]