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

ListBox 到 TreeView 拖放

starIconstarIconstarIconemptyStarIconemptyStarIcon

3.00/5 (18投票s)

2006年5月23日

CPOL

6分钟阅读

viewsIcon

128902

downloadIcon

2988

在本文中,我们将学习如何将 ListBox 中的一个项拖放到 TreeView 中。我们还将讨论如何在 TreeView 中创建文件夹以及删除文件夹。

引言

在本文中,我们将学习如何将 ListBox 中的一个项拖放到 TreeView 中。我们还将讨论如何在 TreeView 中创建文件夹以及删除文件夹。

模块思路

该模块使用 SQL Server 2000 的 NorthWind 数据库中的 Customers 表中的“ContactName”值填充 ListBox。在 TreeView 中,有一个名为“Country”的根文件夹。通过单击“NewFolder”按钮,用户可以创建文件夹在“Country”文件夹下,并可以将其命名为相应的国家名称。当程序运行时,您将看到以下屏幕

图 (a) 初始拖放屏幕

拖放操作后,您将看到类似以下屏幕截图的内容

图 (b) 最终拖放屏幕

可以在用户创建的文件夹下拖放 ListBox 中列出的客户。客户只能拖放到文件夹下。但是,TreeView 中列出的客户可以拖放到TreeView 内部。为了区分TreeView 中的客户和不在TreeView 中的客户,当客户被拖放到TreeView 中时,模块会将 ListBox 中的客户颜色从蓝色更改为黑色。用户可以通过单击“DeleteFolder”按钮来删除文件夹。这样做会改变此删除文件夹下的 ListBox 中项的颜色。

在此模块中,不同控件的名称为

  • lstCustListBox
  • trvCntryTreeView

拖放操作

在从 ListBox 拖动项的操作中,以下事件参与其中

ListBox_MouseDown

当鼠标指针位于控件上且按下鼠标按钮时,会发生此事件。我们使用此事件来捕获正在从 ListBox 拖动的项。以下代码行可完成此操作

lstCust.Items(lstCust.IndexFromPoint(e.X, e.Y)).ToString()

其中 X 获取鼠标单击的 x 坐标,Y 获取鼠标单击的 y 坐标。IndexFromPoint 返回指定坐标处项的零基索引。

DoDragDrop Method: Begins a drag-and-drop operation.
Public Function DoDragDrop( _
   ByVal data As Object, _
   ByVal allowedEffects As DragDropEffects _
) As DragDropEffects

参数

  • data - 要拖动的数据。
  • allowedEffects - DragDropEffects 值之一。

    allowedEffects 参数决定了可以发生哪些拖动操作。

在我们的模块中,我们使用了以下代码行

DoDragDrop(strItem, DragDropEffects.All)

DragDropEffects 指定拖放操作的效果。DragDropEffects 的成员如下所示

  • All - 数据被复制,从拖动源中删除,并在放置目标中滚动。
  • Copy - 数据被复制到放置目标。
  • Link - 来自拖动源的数据链接到放置目标。
  • Move - 来自拖动源的数据被移动到放置目标。
  • None - 放置目标不接受数据。
  • Scroll - 放置目标中的滚动即将开始或正在进行中。

在从 ListBox 将项拖放到 TreeView 的放置操作中,以下事件参与其中

trvCntry_DragEnter

当一个对象被拖动到控件的边界内时,会发生此事件。我们在该事件中编写了以下代码行

If e.Data.GetDataPresent(DataFormats.Text) Then
    e.Effect = DragDropEffects.Move
Else
    e.Effect = DragDropEffects.None
End If
  • e.Data 获取 IDataObject(提供一种与格式无关的数据传输机制),其中包含与此事件相关的数据。
  • e.Data.GetDataPresent:我们可以使用 GetDataPresent 方法来确定数据是否符合数据正在被拖动的控件的格式要求。
  • e.Effect 获取或设置拖动事件目标允许的拖放操作。

trvCntry_DragDrop

拖放操作完成时会发生此事件。我们在该事件中编写了以下代码行。我们将拖动的项存储在一个虚拟节点中,以便将其放置在 TreeView

strNodeDragged = CType(e.Data.GetData(strDummy.GetType), String)
DragNode = New TreeNode(strNodeDragged)

接下来,我们查找要放置项的 TreeView 中的目标项

position.X = e.X
position.Y = e.Y

PointToClient 将指定的屏幕点转换为客户端坐标。

position = trvCntry.PointToClient(position)
DropNode = Me.trvCntry.GetNodeAt(position)

我们按如下方式验证目标 TreeNode。它应该是 RootNode

If IsNothing(DropNode) Or DropNode.Text = "Country" Then
    Exit Sub
End If

为了确保项只能拖放到文件夹上,我们通过编辑 TreeNodeTag 属性来为项分配“N”,为文件夹节点分配“Y”,如下所示

If IsNothing(DragNode.Tag) Then
    DragNode.Tag = "N"
End If

现在,我们的下一个任务是检查拖动的项是否已在 TreeView 中。我们通过调用 ExistInTreeView () 方法来实现,如下所示

'*************************************************************
    ' Function Name :   ExistInTreeView
    ' Purpose       :   This Function Removes The DragNode
    '                   from the tree from its Previous Place
    ' Input         :   DragNode,Node
    ' Output        :   Integer
    ' Author        :   Ujwal Watgule
    ' Date          :   6th May  2006
    ' Modification History
    ' --------------------------------------------------------
'*************************************************************
Private Function ExistInTreeView(ByVal node As TreeNode, _
        ByVal nddrag As TreeNode) As Integer
    Dim anode As TreeNode
    Try
        anode = New TreeNode()
        For Each anode In node.Nodes
            If Trim(anode.Text) = Trim(nddrag.Text) Then
                trvCntry.Nodes.Remove(anode)
                Return sThree

            End If
            If anode.Nodes.Count > 0 Then
                ExistInTreeView(anode, nddrag)
            End If
            If Trim(anode.Text) = Trim(nddrag.Text) Then
                trvCntry.Nodes.Remove(anode)
                Return sThree

            End If
        Next
    Catch ex As Exception
        Throw ex
    End Try
End Function

如下所示,我们遍历 TreeView 的每个节点,并确保被拖动的节点从其先前的父文件夹中移除。

mTrNode = New TreeNode()
For Each mTrNode In trvCntry.Nodes
    ExistInTreeView(mTrNode, DragNode)
Next

现在,我们可以将拖动的项附加到 TreeView 的目标节点。

如果目标节点是文件夹节点,则可以使用以下代码行插入拖动的项。但是,如果目标节点不是文件夹节点,则必须将拖动的项插入到目标节点的父节点中。如下面的代码行所示,我们将拖动项的 Tag 属性设置为“N”,其含义我们已解释过。

If DropNode.Tag = "Y" Then
    DropNode.Nodes.Insert(DropNode.Index + 1, DragNode)
    DragNode.Tag = "N"
    DragNode.ImageIndex = 5
    DragNode.SelectedImageIndex = 5
    DropNode.Expand()
Else
    DropNode.Parent.Nodes.Insert(DropNode.Index + 1, DragNode)
    DragNode.Tag = "N"
    DragNode.ImageIndex = 5
    DragNode.SelectedImageIndex = 5
    DropNode.Expand()
End If

我们还已将节点的 ImageIndexSelectedImageIndex 属性设置为“5”,以便在选中或未选中模式下,文件夹图标都不会出现在它们前面。

现在,该项已成功放置在目标文件夹下。剩余的任务是反映 ListBox 中相应项的正确项路径。我们使用 UpdateListItem 方法将文件夹路径附加到 ListBox 中作为父级的相应项。

新建文件夹按钮

我们可以使用“新建文件夹”按钮在“Country”文件夹下添加新节点。我们在“新建文件夹”按钮的 Click 事件中编写了以下代码行。为了确保文件夹仅在文件夹节点下创建,我们检查所选节点的 Tag 属性。如果它是“Y”,则该节点有资格充当其他节点的父节点。

'Make sure the folder is being created under folder node only
If trvCntry.SelectedNode.Tag = "Y" Then
    SubFolder = New TreeNode()
'If node selected is the last node 
If IsNothing(trvCntry.SelectedNode.LastNode) Then
    trvCntry.SelectedNode.Nodes.Insert(
         trvCntry.SelectedNode.Index + 1, SubFolder)
    trvCntry.SelectedNode.Expand()
Else
    trvCntry.SelectedNode.Nodes.Insert(
         trvCntry.SelectedNode.LastNode.Index + 1, SubFolder)
    trvCntry.SelectedNode.Expand()
End If
SubFolder.Tag = "Y"
SubFolder.ImageIndex = 0
SubFolder.Text = "NewFolder"
trvCntry.SelectedNode = SubFolder
trvCntry.LabelEdit = True
trvCntry.SelectedNode.BeginEdit()
SubFolder.NodeFont = mFnt
End If

删除文件夹按钮

“删除文件夹”按钮允许我们删除一个文件夹,从而刷新该文件夹下的任何其他项(即,它们的颜色从黑色变为蓝色)在 ListBox 中。如下面的代码片段所示,不允许用户删除“Country”文件夹。

If trvCntry.SelectedNode.Text = "Country" Then
    Exit Sub
End If
If trvCntry.SelectedNode.Tag = "Y" Then
    DeleteItems(trvCntry.SelectedNode)
    trvCntry.SelectedNode.Remove()
End If

现在,为了刷新要删除的文件夹下的项,我们调用 DeleteItems() 方法

'*****************************************************
    ' Function Name :   DeleteItems
    ' Purpose       :   This Subroutine Deletes
    '                   The item From the Treeview
    ' Input         :   Treenode
    ' Output        :   Nothing
    ' Author        :   Ujwal Watgule
    ' Date          :   11th May  2006
'*****************************************************
Private Sub DeleteItems(ByVal mNode As TreeNode)
    Dim aNode As TreeNode
    Try
        For Each aNode In mNode.Nodes
            DeleteItems(aNode)
            RefreshList(aNode.Text)
        Next
    Catch ex As Exception
        Throw ex
    End Try
End Sub

DeleteItems() 方法又调用 RefreshList 方法,如下所示

'*********************************************************
' Function Name :   RefreshList
' Purpose       :   This Subroutine Refreshes The Listbox 
' Input         :   Items Name
' Output        :   Nothing
' Author        :   Ujwal Watgule
' Date          :   11th May 2006
'*********************************************************
Private Sub RefreshList(ByVal mItem As String)
    Dim strRefreshListItem As String
    Dim strChkItem As String
    Dim intCntr, icntr As Integer
    Try
        For intCntr = 0 To lstCust.Items.Count - 1
            strRefreshListItem = lstCust.Items(intCntr)
            For icntr = 0 To strRefreshListItem.Length - 1
                If mItem = strRefreshListItem.Substring(0, icntr) Then
                    strChkItem = mItem
                    lstCust.Items.RemoveAt(intCntr)
                    lstCust.Items.Insert(intCntr, (strChkItem))
                    lstCust.Refresh()
                    Exit For
                End If
            Next
        Next
    Catch ex As Exception
        Throw ex
    End Try
End Sub

结论

在本文中,我们了解了 ListBoxTreeView 在拖放操作中参与的事件。我们还看到了如何在 TreeView 中创建新文件夹以及删除文件夹的步骤。在我的下一篇文章中,我们将学习如何将树形结构保存在数据库中并在运行时进行填充。在此之前,祝您一切顺利。

© . All rights reserved.