Come ottenere un elenco di tutti i nodi figlio in un TreeView in.NET




vb.net tree-nodes (8)

Il metodo di Adrian è fantastico. Funziona abbastanza velocemente e ha funzionato meglio rispetto all'approccio di ricorsione. Ho fatto una traduzione in VB. Ho imparato molto da questo. Spero che qualcuno ne abbia ancora bisogno.

Per usarlo semplicemente:

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

Ecco il codice, CHEERS! :

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

Ho un controllo TreeView nella mia applicazione WinForms .NET che ha più livelli di childnodes che hanno childnodes con più childnodes, senza profondità definita. Quando un utente seleziona un nodo genitore (non necessariamente a livello di root), come posso ottenere un elenco di tutti i nodi che beneficiano del nodo genitore?

Ad esempio, ho iniziato con questo:

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

Il problema è che questa profondità del loop è definita e sto solo ottenendo i nodi che sono scesi di tre livelli. Cosa succede se la volta successiva che l'utente seleziona un nodo genitore, ci sono sette livelli?


Answer #1

Se qualcuno ancora vuole fare l'approccio di ricorsione, usando il codice di Jop e mantenendo i TreeNodes (in modo da poter usare le proprietà .tag, .name, .checked o .text) ecco la mia versione

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

Answer #2
nodParent As TreeNode
'nodParent = your parent Node
tvwOpt.Nodes.Find(nodParent.Name, True)

Questo è tutto


Answer #3

Ecco un frammento di codice che uso per eseguire questa attività dalla mia libreria principale. Ti consente di elencare i nodi prima o dopo la profondità senza ricorrere alla ricorsione, che ha il sovraccarico di costruire gli stack nel motore JIT. È molto veloce.

Per usarlo basta andare:

Elenco <TreeNode> nodes = TreeViewUtils.FlattenDepth (albero);

Mi dispiace che tu VB teste, non posso dare un esempio, ma sono sicuro che ci riuscirai.

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;
    }

}

Answer #4

hai bisogno di una funzione ricorsiva per fare questo [o un equivalente di ciclo, ma la versione ricorsiva è più semplice] - pseudocodice:

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

Answer #5

Ik heb de code omgezet naar vb.net ha incontrato dit als resultaat ... suc6

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

Answer #6

Ho un metodo di estensione che uso per questo:

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 #, ma potrebbe essere referenziato da VB o convertito ad esso.


Answer #7

Usa la ricorsione

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




tree-nodes