Как получить список всех дочерних узлов в TreeView в .NET - PullRequest
15 голосов
/ 07 октября 2008

В моем приложении 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

Проблема в том, что эта глубина петли определена, и я закапываю узлы только на три уровня. Что если в следующий раз, когда пользователь выберет родительский узел, будет семь уровней?

Ответы [ 9 ]

18 голосов
/ 07 октября 2008

Использовать рекурсию

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
13 голосов
/ 26 февраля 2009

Вот фрагмент кода, который я использую для выполнения этой задачи из моей базовой библиотеки.
Это позволяет вам перечислять узлы либо по глубине, либо по дыханию в первую очередь без использования рекурсии, что накладывает накладные расходы на создание стековых кадров в движке 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;
    }
}
13 голосов
/ 07 октября 2008

вам нужна рекурсивная функция, чтобы сделать это [или эквивалент цикла, но рекурсивная версия проще] - псевдокод:

function outputNodes(Node root)
    writeln(root.Text)
    foreach(Node n in root.ChildNodes)
        outputNodes(n)
    end
end
12 голосов
/ 09 июня 2009

У меня есть метод расширения, который я использую для этого:

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 или конвертировать в него.

3 голосов
/ 06 октября 2015

метод Адриана, это круто. Работает довольно быстро и работает лучше, чем рекурсивный подход. Я сделал перевод на 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
2 голосов
/ 09 июня 2009

Я преобразовал код в 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
1 голос
/ 14 декабря 2016

Обычно получение значения в указанном узле представляет интерес для программистов. Это можно получить следующим образом. Предполагается, что у вас есть элемент управления TextBox с именем texbox1 и элемент управления TreeView с именем treeview1.Following вернет значение текста на уровне узлов 0 .

textbox1.Text = treeview1.nodes(0).Text.ToString()
1 голос
/ 06 октября 2015

Если кто-то все еще хочет использовать рекурсивный подход, используя код 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
1 голос
/ 19 июня 2010
nodParent As TreeNode
'nodParent = your parent Node
tvwOpt.Nodes.Find(nodParent.Name, True)

Вот так

...