【问题标题】:How to get a list of all child nodes in a TreeView in .NET如何在 .NET 中获取 TreeView 中所有子节点的列表
【发布时间】:2010-09-15 16:35:21
【问题描述】:

我的 WinForms .NET 应用程序中有一个 TreeView 控件,该控件具有多个级别的子节点,这些子节点的子节点具有更多子节点,没有定义的深度。当用户选择任何父节点(不一定在根级别)时,如何获取该父节点下所有节点的列表?

例如,我是这样开始的:

Dim nodes As List(Of String)

For Each childNodeLevel1 As TreeNode In parentNode.Nodes
    For Each childNodeLevel2 As TreeNode In childNodeLevel1.Nodes
        For Each childNodeLevel3 As TreeNode In childNodeLevel2.Nodes
            nodes.Add(childNodeLevel3.Text)
        Next
    Next
Next

问题是这个循环深度是定义的,我只是把节点埋在三个层次上。如果下次用户选择父节点时,有七级呢?

【问题讨论】:

    标签: .net vb.net treeview tree-nodes


    【解决方案1】:

    使用递归

    Function GetChildren(parentNode as TreeNode) as List(Of String)
      Dim nodes as List(Of String) = New List(Of String)
      GetAllChildren(parentNode, nodes)
      return nodes
    End Function
    
    Sub GetAllChildren(parentNode as TreeNode, nodes as List(Of String))
      For Each childNode as TreeNode in parentNode.Nodes
        nodes.Add(childNode.Text)
        GetAllChildren(childNode, nodes)
      Next
    End Sub
    

    【讨论】:

    • 我建议不要调用这个GetChildren,因为它不仅会得到孩子(即直接在当前节点下的节点),还会得到孙子、曾孙等。为清楚起见,我发现为所有后代设置GetDescendants 更好,为下面的直接级别设置GetChildren
    • 我更改了它,而不是字符串列表,我让它返回实际的 TreeNodes 以便以后访问。谢谢!
    【解决方案2】:

    您需要一个递归函数来执行此操作 [或等效的循环,但递归版本更简单] - 伪代码:

    function outputNodes(Node root)
        writeln(root.Text)
        foreach(Node n in root.ChildNodes)
            outputNodes(n)
        end
    end
    

    【讨论】:

    • 这段代码 sn-p 比我大学的老师更能学会递归函数。
    【解决方案3】:

    我有一个用于此的扩展方法:

    public static IEnumerable<TreeNode> DescendantNodes( this TreeNode input ) {
        foreach ( TreeNode node in input.Nodes ) {
            yield return node;
            foreach ( var subnode in node.DescendantNodes() )
                yield return subnode;
            }
    }
    

    它是 C#,但可以从 VB 中引用或转换为它。

    【讨论】:

      【解决方案4】:

      这是我用来从我的核心库中执行此任务的代码的 sn-p。
      它允许您在不使用递归的情况下列出深度优先或呼吸优先的节点,这具有在 JIT 引擎中构造堆栈帧的开销。它非常快。

      要使用它,只需:

      List< TreeNode > nodes = TreeViewUtils.FlattenDepth(tree);
      

      对不起,你有一个 VB.Net 标签;我不能举个例子,但我相信你会解决的。

      public class TreeViewUtils
      {
          /// <summary>
          /// This static utiltiy method flattens all the nodes in a tree view using
          /// a queue based breath first search rather than the overhead
          /// of recursive method calls.
          /// </summary>
          /// <param name="tree"></param>
          /// <returns></returns>
          public static List<TreeNode> FlattenBreath(TreeView tree) {
              List<TreeNode> nodes = new List<TreeNode>();
      
              Queue<TreeNode> queue = new Queue<TreeNode>();
      
              //
              // Bang all the top nodes into the queue.
              //
              foreach(TreeNode top in tree.Nodes) {
                  queue.Enqueue(top);
              }
      
              while(queue.Count > 0) {
                  TreeNode node = queue.Dequeue();
                  if(node != null) {
                      //
                      // Add the node to the list of nodes.
                      //
                      nodes.Add(node);
      
                      if(node.Nodes != null && node.Nodes.Count > 0) {
                          //
                          // Enqueue the child nodes.
                          //
                          foreach(TreeNode child in node.Nodes) {
                              queue.Enqueue(child);
                          }
                      }
                  }
              }
              return nodes;
          }
      
          /// <summary>
          /// This static utiltiy method flattens all the nodes in a tree view using
          /// a stack based depth first search rather than the overhead
          /// of recursive method calls.
          /// </summary>
          /// <param name="tree"></param>
          /// <returns></returns>
          public static List<TreeNode> FlattenDepth(TreeView tree) {
              List<TreeNode> nodes = new List<TreeNode>();
      
              Stack<TreeNode> stack = new Stack<TreeNode>();
      
              //
              // Bang all the top nodes into the queue.
              //
              foreach(TreeNode top in tree.Nodes) {
                  stack.Push(top);
              }
      
              while(stack.Count > 0) {
                  TreeNode node = stack.Pop();
                  if(node != null) {
      
                      //
                      // Add the node to the list of nodes.
                      //
                      nodes.Add(node);
      
                      if(node.Nodes != null && node.Nodes.Count > 0) {
                          //
                          // Enqueue the child nodes.
                          //
                          foreach(TreeNode child in node.Nodes) {
                              stack.Push(child);
                          }
                      }
                  }
              }
              return nodes;
          }
      }
      

      【讨论】:

      • 我会调查的。感谢分享,阿德里安!
      • 最后是一种非递归的方法。非常感谢。
      【解决方案5】:
      nodParent As TreeNode
      'nodParent = your parent Node
      tvwOpt.Nodes.Find(nodParent.Name, True)
      

      就是这样

      【讨论】:

        【解决方案6】:

        Adrian 的方法太棒了。工作得非常快并且比递归方法工作得更好。我已经完成了对 VB 的翻译。我从中学到了很多。希望有人仍然需要它。

        简单地使用它:

        Dim FlattenedNodes As List(Of TreeNode) = clTreeUtil.FlattenDepth(Me.TreeView1) 
        

        这是代码,干杯! :

        Public Class clTreeUtil
        ''' <summary>
        ''' This static utiltiy method flattens all the nodes in a tree view using
        ''' a queue based breath first search rather than the overhead
        ''' of recursive method calls.
        ''' </summary>
        ''' <param name="tree"></param>
        ''' <returns></returns>
        Public Shared Function FlattenBreath(Tree As TreeView) As List(Of TreeNode)
            Dim nodes As List(Of TreeNode) = New List(Of TreeNode)
            Dim queue As Queue(Of TreeNode) = New Queue(Of TreeNode)
        
            ''
            '' Bang all the top nodes into the queue.
            ''
            For Each top As TreeNode In Tree.Nodes
                queue.Enqueue(top)
            Next
        
            While (queue.Count > 0)
                Dim node As TreeNode = queue.Dequeue()
                If node IsNot Nothing Then
                    ''
                    '' Add the node to the list of nodes.
                    ''
                    nodes.Add(node)
        
                    If node.Nodes IsNot Nothing And node.Nodes.Count > 0 Then
                        ''
                        '' Enqueue the child nodes.
                        ''
                        For Each child As TreeNode In node.Nodes
                            queue.Enqueue(child)
                        Next
                    End If
                End If
            End While
        
            Return nodes
        End Function
        
        ''' <summary>
        ''' This static utiltiy method flattens all the nodes in a tree view using
        ''' a stack based depth first search rather than the overhead
        ''' of recursive method calls.
        ''' </summary>
        ''' <param name="tree"></param>
        ''' <returns></returns>
        Public Shared Function FlattenDepth(tree As TreeView) As List(Of TreeNode)
            Dim nodes As List(Of TreeNode) = New List(Of TreeNode)
        
            Dim stack As Stack(Of TreeNode) = New Stack(Of TreeNode)
        
            ''
            '' Bang all the top nodes into the queue.
            ''
            For Each top As TreeNode In tree.Nodes
                stack.Push(top)
            Next
        
            While (stack.Count > 0)
                Dim node As TreeNode = stack.Pop()
        
                If node IsNot Nothing Then
        
                    ''
                    '' Add the node to the list of nodes.
                    ''
                    nodes.Add(node)
        
                    If node.Nodes IsNot Nothing And node.Nodes.Count > 0 Then
                        ''
                        '' Enqueue the child nodes.
                        ''
                        For Each child As TreeNode In node.Nodes
                            stack.Push(child)
                        Next
                    End If
                End If
        
            End While
        
            Return nodes
        End Function
        
        End Class
        

        【讨论】:

          【解决方案7】:

          我已将代码转换为VB.Net,结果如下:

          Public Function FlattenBreadth(ByVal tree As TreeView) As List(Of TreeNode)
              Dim nodes As New List(Of TreeNode)
              Dim queue As New Queue(Of TreeNode)
              Dim top As TreeNode
              Dim nod As TreeNode
              For Each top In tree.Nodes
                  queue.Enqueue(top)
              Next
              While (queue.Count > 0)
                  top = queue.Dequeue
                  nodes.Add(top)
                  For Each nod In top.Nodes
                      queue.Enqueue(nod)
                  Next
              End While
              FlattenBreadth = nodes
          End Function
          

          【讨论】:

            【解决方案8】:

            如果有人仍然想做递归方法,使用 Jop 的代码,并保留 TreeNodes(这样你就可以使用他们的 .tag、.name、.checked 或 .text 属性),这里是我的版本

            Public Shared Function GetChildren(objTree As TreeView) As List(Of TreeNode)
                Dim nodes As List(Of TreeNode) = New List(Of TreeNode)
                For Each parentNode As TreeNode In objTree.Nodes
                    nodes.Add(parentNode)
                    GetAllChildren(parentNode, nodes)
                Next
            
                Return nodes
            End Function
            
            Public Shared Sub GetAllChildren(parentNode As TreeNode, nodes As List(Of TreeNode))
                For Each childNode As TreeNode In parentNode.Nodes
                    nodes.Add(childNode)
                    GetAllChildren(childNode, nodes)
                Next
            End Sub
            

            【讨论】:

              【解决方案9】:

              通常在指定节点获取值是程序员感兴趣的。这可以通过如下方式获取。假设你有一个名为 texbox1 的 TextBox 控件和一个名为 treeview1 的 TreeView 控件。以下将返回节点级别 0 的文本值.

              textbox1.Text = treeview1.nodes(0).Text.ToString()
              

              【讨论】:

                【解决方案10】:

                在 .Net WindowsForm TreeView 中具有 Find() 方法和可选标志 'searchAllChildren'

                在 asp.net 中却没有。 为了得到相同的结果,我使用它(类似于 Keith 的答案,但在输入中我使用 TreeView)

                public static IEnumerable<TreeNode> DescendantNodes2(this TreeView input)
                {
                    foreach (TreeNode node in input.Nodes)
                    {
                        yield return node;
                        foreach (var subnode in node.DescendantNodes())
                            yield return subnode;
                    }
                }
                private static IEnumerable<TreeNode> DescendantNodes(this TreeNode input)
                {
                    foreach (TreeNode node in input.ChildNodes)
                    {
                        yield return node;
                        foreach (var subnode in node.DescendantNodes())
                            yield return subnode;
                    }
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多