Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Introduction to TreeView Drag and Drop (VB.NET)

0.00/5 (No votes)
8 Dec 2004 2  
Provide drag and drop functionalitly to TreeView controls.

Introduction

TreeView controls are extremely common in applications where it is necessary to present any sort of hierarchy to a user. Usually, the nature of such a hierarchy requires that users have the ability to reorganize it; drag and drop operations providing a natural solution. This article provides an introduction to implementing drag and drop functionality to a TreeView control.

Getting Started

The code in this article assumes you have a form with a TreeView control, this needs to be populated with some TreeNodes (the demo project available at the top of the article provides a method to randomly generate a TreeNode hierarchy). Ensure that the TreeView can accept objects dragged onto it by setting the AllowDrop property to True.

Initiating the Drag

When the user begins the drag action on a TreeNode, the ItemDrag event is fired, we need to handle this:

    Public Sub TreeView1_ItemDrag(ByVal sender As System.Object, _
        ByVal e As System.Windows.Forms.ItemDragEventArgs) _
        Handles TreeView1.ItemDrag
        
        'Set the drag node and initiate the DragDrop 
        DoDragDrop(e.Item, DragDropEffects.Move)
        
    End Sub

Here we are initiating a drag operation by calling the DoDragDrop method, specifying the TreeNode object being dragged and specifying the Move operation the user will perform if the drag drop is completed. Note that the DragDropEffects enumeration merely describes the cursors (effects) that can be presented during the operation, it will not enforce that the object will ultimately be moved as a result of the successful drag drop operation.

Dragging Over the Control

With the drag operation under way, the TreeView must now react when an object is dragged over it. When this occurs, the DragEnter event is fired that we must handle:

    Public Sub TreeView1_DragEnter(ByVal sender As System.Object, _
        ByVal e As System.Windows.Forms.DragEventArgs) _
        Handles TreeView1.DragEnter

        'See if there is a TreeNode being dragged
        If e.Data.GetDataPresent("System.Windows.Forms.TreeNode", _
            True) Then
            'TreeNode found allow move effect
            e.Effect = DragDropEffects.Move
        Else
            'No TreeNode found, prevent move
            e.Effect = DragDropEffects.None
        End If

    End Sub

All we are doing here is checking if there is an object present in the drag drop operation that we are happy to be dropped onto the TreeView, in this case a TreeNode. If a TreeNode is found, then we specify that the Move effect will be displayed on the cursor, otherwise we specify that the None effect will be displayed. Note, you may only select the effect(s) that were specified when the drag drop operation was initiated with the DoDragDrop method (see Initiating the Drag above).

It is important to check that the object of the type you are expecting is present in the drag drop data (in this case, a TreeNode). In this example, we only have one control that is initiating a drag drop operation. However, on a form, there may be many other controls calling the DoDragDrop method; by setting the AllowDrop property to True on a control, you are specifying that it will react whenever any object is dragged over it.

Validating the Drop Target

Above, we looked at ensuring only TreeNodes can be dragged over the TreeView. However, it is also important to ensure that a particular TreeNode within the TreeView is a valid target for the drag drop operation. Therefore, we have to validate the TreeNode as the cursor passes over it by handling the DragOver event:

    Public Sub TreeView1_DragOver(ByVal sender As System.Object, _
        ByVale As DragEventArgs) _
        Handles TreeView1.DragOver

        'Check that there is a TreeNode being dragged 
        If e.Data.GetDataPresent("System.Windows.Forms.TreeNode", _
               True) = False Then Exit Sub

        'Get the TreeView raising the event (incase multiple on form)
        Dim selectedTreeview As TreeView = CType(sender, TreeView)

        'As the mouse moves over nodes, provide feedback to 
        'the user by highlighting the node that is the 
        'current drop target
        Dim pt As Point = _
            CType(sender, TreeView).PointToClient(New Point(e.X, e.Y))
        Dim targetNode As TreeNode = selectedTreeView.GetNodeAt(pt)

        'See if the targetNode is currently selected, 
        'if so no need to validate again
        If Not (selectedTreeview.SelectedNode Is targetNode) Then
            'Select the    node currently under the cursor
            selectedTreeview.SelectedNode = targetNode

            'Check that the selected node is not the dropNode and
            'also that it is not a child of the dropNode and 
            'therefore an invalid target
            Dim dropNode As TreeNode = _
                CType(e.Data.GetData("System.Windows.Forms.TreeNode"), _
                TreeNode)
                
                Do Until targetNode Is Nothing
                    If targetNode Is dropNode Then
                        e.Effect = DragDropEffects.None
                        Exit Sub
                    End If
                    targetNode = targetNode.Parent
                Loop
            End If

            'Currently selected node is a suitable target
            e.Effect = DragDropEffects.Move
        End If

    End Sub

Firstly, we are checking that there is a TreeNode object in the drag drop operation. If there is not, we aren't going any further; there is no need to even change the effect because the TreeView would have taken care of that during the DragEnter event handler.

Then next stage is to get the TreeView that fired the event (important if this method is handling multiple TreeView controls on a single form), and work out the TreeNode that is currently under the cursor using the GetNodeAt function. Finally, we must ensure that the TreeNode under the cursor is not the TreeNode that is being dragged or a child of that TreeNode. This is important; if we attempt to drop a TreeNode onto itself or a ChildNode, then the node and its siblings would all just vanish.

Provided the TreeNode under the cursor is a valid drop target, we provide feedback to the user by setting the Move effect.

Performing the Drop

Finally, we need to drop the the TreeNode to complete the operation. This is accomplished by handling the DragDrop event fired by the TreeView:

    Public Sub TreeView1_DragDrop(ByVal sender As System.Object, _
        ByVal e As System.Windows.Forms.DragEventArgs) _
        Handles TreeView1.DragDrop

        'Check that there is a TreeNode being dragged
        If e.Data.GetDataPresent("System.Windows.Forms.TreeNode", _
              True) = False Then Exit Sub

        'Get the TreeView raising the event (incase multiple on form)
        Dim selectedTreeview As TreeView = CType(sender, TreeView)

        'Get the TreeNode being dragged
        Dim dropNode As TreeNode = _
              CType(e.Data.GetData("System.Windows.Forms.TreeNode"), _
              TreeNode)

        'The target node should be selected from the DragOver event
        Dim targetNode As TreeNode = selectedTreeview.SelectedNode

        'Remove the drop node from its current location
        dropNode.Remove()

        'If there is no targetNode add dropNode to the bottom of
        'the TreeView root nodes, otherwise add it to the end of
        'the dropNode child nodes
        If targetNode Is Nothing Then
            selectedTreeview.Nodes.Add(dropNode)
        Else
            targetNode.Nodes.Add(dropNode)
        End If

        'Ensure the newley created node is visible to
        'the user and select it
        dropNode.EnsureVisible()
        selectedTreeview.SelectedNode = dropNode

    End Sub

As above, we firstly check that there is a TreeNode present in the drop data and get the TreeView firing the event in case of multiple TreeViews handled by the method. We then locate the node that will be the target of the drop and remove the node that is being moved from its original location.

If there is no target node, we assume the target to be the TreeView itself, and therefore add the node at the end of the TreeView.Nodes collection. Otherwise, we add the node to the end of the target TreeNode.Nodes collection.

Finally, by calling the EnsureVisible method, all ParentNodes of the node we just added will be expanded, making sure that the node is not hidden. Selecting the dropped node will provide feedback to the user by highlighting it once the operation is complete.

Supporting Multiple TreeViews

The code in this article has been designed to allow multiple TreeView controls to support drag and drop operation on the form. To add support for multiple TreeView controls, complete the following:

  1. Add a TreeView control to the form
  2. Set its AllowDrop property to True
  3. Amend each of the methods above to handle the relevant events of the new TreeView, for example:
    Public Sub TreeView1_DragDrop(ByVal sender As System.Object, _
        ByVal e As System.Windows.Forms.DragEventArgs) _
        Handles TreeView1.DragDrop, TreeView2.DragDrop

Any number of additional TreeView controls can be added to the form in this way.

Conclusion

I hope this article provides an interesting introduction to Drag and Drop operations. The logic applied in this article can also be applied to other controls allowing a user interface that completely supports Drag and Drop.

Related Articles

If you found this article interesting, you may be interested in other introductory articles relating to the TreeView control:

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here