65.9K
CodeProject 正在变化。 阅读更多。
Home

TreeView 拖放入门 (VB.NET)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (86投票s)

2004年12月8日

CPOL

5分钟阅读

viewsIcon

422843

downloadIcon

5781

为 TreeView 控件提供拖放功能。

引言

TreeView 控件在需要向用户呈现任何形式的层次结构的应用程序中非常常见。通常,这种层次结构的性质要求用户能够对其进行重新组织;拖放操作提供了一种自然的解决方案。本文介绍了如何在 TreeView 控件中实现拖放功能。

入门

本文中的代码假定您有一个带有 TreeView 控件的窗体,该控件需要填充一些 TreeNode(文章顶部的演示项目提供了一种随机生成 TreeNode 层次结构的方法)。通过将 AllowDrop 属性设置为 True,确保 TreeView 可以接受拖放到其上的对象。

发起拖放

当用户在 TreeNode 上开始拖放操作时,会触发 ItemDrag 事件,我们需要处理它。

    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

在这里,我们通过调用 DoDragDrop 方法来发起拖放操作,指定正在拖动的 TreeNode 对象,并指定用户在拖放操作完成后将执行的 Move 操作。请注意,DragDropEffects 枚举仅仅描述了在操作过程中可以显示的游标(效果),它不会强制规定对象最终是否会因为成功的拖放操作而被移动。

拖动到控件上

拖放操作进行中时,TreeView 现在必须对拖动对象到其上时做出响应。发生这种情况时,会触发 DragEnter 事件,我们必须处理它。

    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

我们在这里所做的只是检查拖放操作中是否存在我们乐意将其拖放到 TreeView 上的对象,在本例中是 TreeNode。如果找到了 TreeNode,我们就指定游标上将显示 Move 效果,否则我们就指定显示 None 效果。请注意,您只能选择在调用 DoDragDrop 方法初始化拖放操作时指定的(效果)——(见上文的发起拖放)。

重要的是要检查是否存在您期望的类型的对象在拖放数据中(在本例中是 TreeNode)。在此示例中,我们只有一个控件在发起拖放操作。然而,在一个窗体上,可能有许多其他控件调用 DoDragDrop 方法;通过将控件的 AllowDrop 属性设置为 True,您就指定了它会在任何对象被拖动到它上面时做出响应。

验证放置目标

上面,我们研究了如何确保只有 TreeNodes 可以被拖动到 TreeView 上。然而,确保 TreeView 中的特定 TreeNode 是拖放操作的有效目标也很重要。因此,我们必须通过处理 DragOver 事件来在游标经过 TreeNode 时验证它。

    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

首先,我们检查拖放操作中是否存在 TreeNode 对象。如果不存在,我们就不会继续进行;没有必要改变效果,因为 TreeView 已经在 DragEnter 事件处理程序中处理了。

下一个阶段是获取触发事件的 TreeView(如果此方法处理单个窗体上的多个 TreeView 控件,这一点很重要),并使用 GetNodeAt 函数找出当前在游标下的 TreeNode。最后,我们必须确保在游标下的 TreeNode 不是正在被拖动的 TreeNode 或其子节点。这一点很重要;如果我们尝试将一个 TreeNode 放置到它自身或其子节点上,那么该节点及其同级节点将全部消失。

如果游标下的 TreeNode 是一个有效的放置目标,我们就通过设置 Move 效果来向用户提供反馈。

执行放置

最后,我们需要放置 TreeNode 来完成操作。这可以通过处理 TreeView 触发的 DragDrop 事件来实现。

    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

如上所述,我们首先检查放置数据中是否存在 TreeNode,并获取触发事件的 TreeView(以防方法处理多个 TreeView)。然后,我们定位将成为放置目标的节点,并从其原始位置删除正在移动的节点。

如果不存在目标节点,我们就假定目标是 TreeView 本身,因此将节点添加到 TreeView.Nodes 集合的末尾。否则,我们将节点添加到目标 TreeNode.Nodes 集合的末尾。

最后,通过调用 EnsureVisible 方法,我们将展开刚刚添加的节点的**所有**父节点,确保节点不会被隐藏。选择放置的节点将在操作完成后通过高亮显示来向用户提供反馈。

支持多个 TreeView

本文中的代码旨在允许多个 TreeView 控件在窗体上支持拖放操作。要添加对多个 TreeView 控件的支持,请完成以下步骤:

  1. TreeView 控件添加到窗体
  2. 将其 AllowDrop 属性设置为 True
  3. 修改上述每个方法以处理新 TreeView 的相关事件,例如:
    Public Sub TreeView1_DragDrop(ByVal sender As System.Object, _
        ByVal e As System.Windows.Forms.DragEventArgs) _
        Handles TreeView1.DragDrop, TreeView2.DragDrop

可以通过这种方式向窗体添加任意数量的额外 TreeView 控件。

结论

我希望本文能提供一个有趣的拖放操作入门。本文应用的逻辑也可以应用于其他控件,从而实现一个完全支持拖放的用户界面。

相关文章

如果您觉得这篇文章很有趣,您可能还对其他关于 TreeView 控件的入门文章感兴趣:

© . All rights reserved.