Link to home
Start Free TrialLog in
Avatar of i-Thomas
i-Thomas

asked on

Drag and Drop in Treeview

Hi Experts!

I would like to know how to establish drag and drop functionality within a treeview control.

I need this so that the nodes of the same level in hierarchy can be rearranged by dragging and dropping.


Thanks in advance!
Avatar of RonaldBiemans
RonaldBiemans

Avatar of i-Thomas

ASKER

It is explained for two separate tree view controls.

Does it work also for within the same treeview?
yep, like this

Public Sub TreeView_ItemDrag(ByVal sender As Object, _
                                  ByVal e As ItemDragEventArgs) _
                                  Handles TreeView1.ItemDrag
        DoDragDrop(e.Item, DragDropEffects.Move)
    End Sub
    Public Sub TreeView_DragEnter(ByVal sender As Object, _
                           ByVal e As DragEventArgs) _
                           Handles TreeView1.DragEnter
        e.Effect = DragDropEffects.Move
    End Sub
    Public Sub TreeView_DragDrop(ByVal sender As Object, _
                                  ByVal e As DragEventArgs) _
                                  Handles TreeView1.DragDrop
        Dim NewNode As TreeNode
        If e.Data.GetDataPresent("System.Windows.Forms.TreeNode", False) Then
            Dim pt As Point
            Dim DestinationNode As TreeNode
            pt = CType(sender, TreeView).PointToClient(New Point(e.X, e.Y))
            DestinationNode = CType(sender, TreeView).GetNodeAt(pt)
            NewNode = CType(e.Data.GetData("System.Windows.Forms.TreeNode"), _
                                            TreeNode)
            'If Not DestinationNode.TreeView Is NewNode.TreeView Then
            DestinationNode.Nodes.Add(NewNode.Clone)
            DestinationNode.Expand()
            'Remove original node
            NewNode.Remove()
            'End If
        End If
For the line:

"e.Effect = DragDropEffects.Move"

I get the following Error message:

Error2: 'Effect' is not a member of 'System.Windows.Forms.ItemDragEventArgs'.      

What to do here?
Sorry, it was my mistake. I already found it.


How can I ensure that drag-drop works only for nodes on the same node level? The hierarchy order must remain intact.
Can you please help me with that issue?

Thanks a lot again!
Hi i_thomas,

What do you mean exactly with the same node level (horizontaly, or verticaly)

I mean the following:

Level 1
    Level2
    Level2
    Level2
         Level3
         Level3
         Level3
         Level3
Level1
Level1
    Level2
    Level2


So If I drag a node from level 2, it should be dropable (insert, not replace!) only on nodes with level 2.
Aha, I'll will try something out, I'll be back :-)
Thanks :-)

If it is difficult for you I offer to raise points to 500!


Regards,

i-Thomas
By the way:

Is it possible to adjust the sensitivity of drag-drop, that means how many pixels I have to drag until this is recognized as a drag-drop operation? If too sensitive, ordinare clicking can cause the start of drag-drop...
this seems to work (but I'll see if I can find a more elegant way)


Public Sub TreeView_DragDrop(ByVal sender As Object, _
                                  ByVal e As DragEventArgs) _
                                  Handles TreeView1.DragDrop
        Dim NewNode As TreeNode
        If e.Data.GetDataPresent("System.Windows.Forms.TreeNode", False) Then
            Dim pt As Point
            Dim DestinationNode As TreeNode
            pt = CType(sender, TreeView).PointToClient(New Point(e.X, e.Y))
            DestinationNode = CType(sender, TreeView).GetNodeAt(pt)
            NewNode = CType(e.Data.GetData("System.Windows.Forms.TreeNode"), _
                                            TreeNode)
            Dim ar1(), ar2() As String
            ar1 = NewNode.FullPath.Split(New Char() {"\"})
            ar2 = DestinationNode.FullPath.Split(New Char() {"\"})
            If ar1.GetUpperBound(0) - 1 = ar2.GetUpperBound(0) Then
                DestinationNode.Nodes.Add(NewNode.Clone)
                DestinationNode.Expand()
                NewNode.Remove()
            End If
        End If


    End Sub
This is much better

Public Function NodeatLevel(ByVal node As TreeNode) As Integer
        Dim level As Integer = 0
        While Not node Is Nothing
            node = node.Parent
            level = level + 1
        End While
        Return level
    End Function

Public Sub TreeView_DragDrop(ByVal sender As Object, _
                                  ByVal e As DragEventArgs) _
                                  Handles TreeView1.DragDrop
        Dim NewNode As TreeNode
        If e.Data.GetDataPresent("System.Windows.Forms.TreeNode", False) Then
            Dim pt As Point
            Dim DestinationNode As TreeNode
            pt = CType(sender, TreeView).PointToClient(New Point(e.X, e.Y))
            DestinationNode = CType(sender, TreeView).GetNodeAt(pt)
            NewNode = CType(e.Data.GetData("System.Windows.Forms.TreeNode"), _
                                            TreeNode)

            Dim level As Integer = NodeatLevel(NewNode) - 1

            If NodeatLevel(DestinationNode) = level Then
                DestinationNode.Nodes.Add(NewNode.Clone)
                DestinationNode.Expand()
                NewNode.Remove()
            End If

        End If


    End Sub
Ok, we are approching the goal. I raised the points to 500.

At the moment I have to drag a Level2 node onto Level1 node and then it "slips" into Level2 position.

I would like to be able to drag a Level2 node directly to the correct position in another Level2 node branch.

Do you get what I mean?
try this (this will insert it under the newly selected node)

Public Sub TreeView_DragDrop(ByVal sender As Object, _
                                  ByVal e As DragEventArgs) _
                                  Handles TreeView1.DragDrop
        Dim NewNode As TreeNode
        If e.Data.GetDataPresent("System.Windows.Forms.TreeNode", False) Then
            Dim pt As Point
            Dim DestinationNode As TreeNode
            pt = CType(sender, TreeView).PointToClient(New Point(e.X, e.Y))
            DestinationNode = CType(sender, TreeView).GetNodeAt(pt)
            NewNode = CType(e.Data.GetData("System.Windows.Forms.TreeNode"), _
                                            TreeNode)
            Dim level As Integer = NodeatLevel(NewNode)
         
            If NodeatLevel(DestinationNode) = level Then
               
                DestinationNode.Parent.Nodes.Insert(DestinationNode.Index + 1, NewNode.Clone)
                DestinationNode.Expand()
             
                NewNode.Remove()
            End If
        End If
Ok, that works.

One last question ;-)


How can I (generally) set the selection focus to a node?

In this current drag and drop case I would like to have the moved node in selected state.

I also wrote "up" and "down" functions for treenodes so that they can be moved up and down within their branch, but I want them to stay selected.

I found "IsSelected", but this seems to be read only...?
this will keep your dragged node selected, the
treeview1.selectnode = 'yournode is the trick

Public Sub TreeView_DragDrop(ByVal sender As Object, _
                                  ByVal e As DragEventArgs) _
                                  Handles TreeView1.DragDrop
        Dim NewNode As TreeNode
        If e.Data.GetDataPresent("System.Windows.Forms.TreeNode", False) Then
            Dim pt As Point
            Dim DestinationNode As TreeNode
            pt = CType(sender, TreeView).PointToClient(New Point(e.X, e.Y))
            DestinationNode = CType(sender, TreeView).GetNodeAt(pt)
            NewNode = CType(e.Data.GetData("System.Windows.Forms.TreeNode"), _
                                            TreeNode)
            Dim level As Integer = NodeatLevel(NewNode)

            If NodeatLevel(DestinationNode) = level Then

                Dim tn As TreeNode = NewNode.Clone
                DestinationNode.Parent.Nodes.Insert(DestinationNode.Index + 1, tn)
                DestinationNode.Expand()
                TreeView1.SelectedNode = tn

                NewNode.Remove()
            End If

        End If


    End Sub
ASKER CERTIFIED SOLUTION
Avatar of RonaldBiemans
RonaldBiemans

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks a lot again!

This was very helpful indeed! Now I think I will manage with the Treeview ;-)
Glad I could help :-)