Home Search Contact us About us
Title Simple Drap and Drop of items in a Tree control.
Summary This is a poor demonstration of how to implement drag and drop in a tree control to move items and whole branchs arround in a tree control. It does not support moving to other controls or windows.
Contributor John McTainsh
Published 1-Aug-2001
Last updated 1-Aug-2001
Page rating   74% for 7 votes Useless Brilliant

Introduction

Here we will show how to move and copy items on a tree control using drag and drop. This is a very poor hack at dragging and dropping items around a tree control. It works but has the following limitations;

Limitations

  • It is possible to trick the tree by dragging the item off the tree and dropping it somewhere else then returning it.
  • The argument passed as the drag object is only a text path not the actual node.
  • When an item is dragged back onto the tree it is not tracked on the tree.
  • The user can only copy and move nodes around on this tree.

Performing a Drag and Drop

Firstly we will add some items to the tree control. For this example the tree control has been named  m_tree.

/// <summary>
/// Setup the tree control items when the form is loaded.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, System.EventArgs e)
{
    m_tree.Nodes.Add( "Root" );
    m_tree.Nodes[ 0 ].Nodes.Add( "First sub node" );
    m_tree.Nodes[ 0 ].Nodes.Add( "Second sub node" );
    m_tree.Nodes.Add( "Second root node" );
}

The following code will perform the drag and drop operation as follows;

  • ItemDrag is what starts the drag. Here we decide to copy or move depending on the state of the CTRL key.
  • DragEnter is called when the drag starts and sets the type of operations that can happen with this tree.
  • DragOver is called when ever the mouse moves. This allows the items in the tree to be highlighted when the mouse moves over them.
  • DragDrop is where it all ends and the drag action results in a move or a copy.
// This variable holds the item currently being moved.
private TreeNode m_treeNodeDrag = null;

/// <summary>
/// Here we begin the move operation. We take the current item and determine
/// the type of drag.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void m_tree_ItemDrag(object sender, System.Windows.Forms.ItemDragEventArgs e)
{
    // Record who is dragging.
    m_treeNodeDrag = (TreeNode)e.Item;
    
    // Move or if CTRL pressed Copy
    DragDropEffects dropEffect = DragDropEffects.Move;

    if( ( Control.ModifierKeys & Keys.Control ) != 0 )
        dropEffect = DragDropEffects.Copy;

    // Record who is moving to cross check with drop.
    m_tree.DoDragDrop( m_treeNodeDrag.FullPath, dropEffect );
}

/// <summary>
/// This is called once at the start of the drag operation. It sets the 
/// type of cursor to display.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void m_tree_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
    e.Effect = DragDropEffects.Move | DragDropEffects.Copy;
}

/// <summary>
/// This is called when ever the mouse moves when something is being
/// dragged over the tree control.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void m_tree_DragOver(object sender, System.Windows.Forms.DragEventArgs e)
{
    Point pt = new Point( e.X, e.Y );
    // Verify it is the correct data source.
    if( m_treeNodeDrag.FullPath == e.Data.GetData(DataFormats.Text).ToString() )
        m_tree.SelectedNode = m_tree.GetNodeAt( m_tree.PointToClient( pt ) );
    else
        e.Effect = DragDropEffects.None;
}

/// <summary>
/// This is called when an item is dropped onto the tree control window. Only
/// if the Effect is Copy or Move will the item be dropped causing this
/// method to activate.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void m_tree_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
    MessageBox.Show("Drop"+e.ToString(), sender.ToString());
    // Lock screen during change. (Only necessary for large moves)
    Cursor.Current = Cursors.WaitCursor;
    m_tree.BeginUpdate();

    Point pt = new Point( e.X, e.Y );
    TreeNode tnDestination = m_tree.GetNodeAt( m_tree.PointToClient( pt ) );
    m_tree.SelectedNode = tnDestination;
    tnDestination.Nodes.Add( (TreeNode)m_treeNodeDrag.Clone() );
    tnDestination.Expand();
    if( e.AllowedEffect == DragDropEffects.Move )
        m_treeNodeDrag.Remove();

    // End the updating stage
    m_tree.EndUpdate();
    Cursor.Current = Cursors.Default;

    m_treeNodeDrag = null;
}

Using the private member variable m_treeNodeDrag to indicate which node is moving is a bad thing. It should be some sort of item what is serialised to the drag object data.

Comments Date
Home Search Contact us About us