将Treeview节点集合展平为List而不递归

时间:2015-01-26 18:44:36

标签: vb.net linq treeview

希望这不是一个重复的问题。我查看并发现了类似的问题,但在这种情况下还不够。 我有许多树视图控件,并且可以出于各种原因递归遍历节点。 但是,我经常需要 遍历节点,就好像它们在列表中一样。 我想创建一个函数,从Nodes集合创建Generic.List(of TreeNode),如果可能的话,没有递归

没有递归纯粹是为了不进行递归而不进行递归 - 我明白可能不可能)

在大规模解决方案中重复使用此函数可以节省大量时间,编码人员可以使用简单的For Each范例遍历节点。

我已经看到了一种使用C#“扁平化”Nodes集合的技术,它使用LINQ和递归,但我不确定语法是否可以干净地转换为VB.NET。因此,如果有任何聪明的VB函数,我可以完成这项任务 - 非常有用。

在SO上有许多类似的问题和非常丰富的答案,如下所示: Enumerating Collections that are not inherently IEnumerable? ...使用某些算法突出显示非常深的树中的堆栈溢出错误。我希望不使用递归的方法不会受到堆栈溢出错误的影响 - 但是,我准备好它可能很长而且笨拙和缓慢。

我也准备好了答案'没有递归就无法做到这一点'。但是,我想使用SO(本论坛)

的力量来确认或否认这一主张

2 个答案:

答案 0 :(得分:2)

这是可能的,而且根本不是很难......

Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        TreeView1.ExpandAll()
        For Each TN As TreeNode In TreeView1.NodesToListWithoutRecursionBecauseWhyNot(TraverseType.BreadthFirst)
            Debug.Print(TN.Text)
        Next
    End Sub

End Class

Public Module Extensions

    Public Enum TraverseType
        BreadthFirst
        DepthFirst
    End Enum

    <Runtime.CompilerServices.Extension()> _
    Public Function NodesToListWithoutRecursionBecauseWhyNot(ByVal TV As TreeView, Optional ByVal Traverse As TraverseType = TraverseType.DepthFirst) As List(Of TreeNode)
        Dim nodes As New List(Of TreeNode)

        Select Case Traverse
            Case TraverseType.BreadthFirst
                Dim Q As New Queue(Of TreeNode)
                For Each TN As TreeNode In TV.Nodes
                    Q.Enqueue(TN)
                Next

                While Q.Count > 0
                    Dim TN As TreeNode = Q.Dequeue
                    nodes.Add(TN)
                    For Each subTN As TreeNode In TN.Nodes
                        Q.Enqueue(subTN)
                    Next
                End While

            Case TraverseType.DepthFirst
                Dim L As New List(Of TreeNode)
                For Each TN As TreeNode In TV.Nodes
                    L.Add(TN)
                Next

                While L.Count > 0
                    Dim TN As TreeNode = L.Item(0)
                    L.RemoveAt(0)
                    nodes.Add(TN)
                    For i As Integer = TN.Nodes.Count - 1 To 0 Step -1
                        L.Insert(0, TN.Nodes(i))
                    Next
                End While
        End Select

        Return nodes
    End Function

End Module

答案 1 :(得分:1)

只需将节点添加到列表中,但同时保持您处理的最后一个节点的位置。当一个节点的直接子节点被添加到列表中时,该节点被视为进程。

Public Function GetAllNodes(ByVal topNode As TreeNode)

    Dim allNodes As New List(Of TreeNode)
    Dim lastProcessPosition As Integer = 0

    allNodes.Add(topNode)

    Do While lastProcessPosition < allNodes.Count
        allNodes.AddRange(allNodes(lastProcessPosition).Nodes)

        lastProcessPosition += 1
    Loop

    Return allNodes
End Function

如果您没有顶级节点,那么只需将该参数替换为开始的节点列表。

Public Function GetAllNodes(ByVal topNodes As TreeNodeCollection)

    Dim allNodes As New List(Of TreeNode)
    Dim lastProcessPosition As Integer = 0

    allNodes.AddRange(topNodes)

    Do While lastProcessPosition < allNodes.Count
        allNodes.AddRange(allNodes(lastProcessPosition).Nodes)

        lastProcessPosition += 1
    Loop

    Return allNodes
End Function

我不确定在使用Nodes属性之前是否必须检查Nothing。

注意:我能够删除此for循环并将其替换为AddRange

'For Each node As TreeNode In allNodes(lastProcessPosition).Nodes
'    allNodes.Add(node)
'Next