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

Ho un controllo TreeView nella mia WinForms .NET applicazione che dispone di più livelli di childnodes che hanno childnodes con più childnodes, senza profondità stabilita. Quando un utente seleziona un qualsiasi nodo padre (non necessariamente al livello principale), come posso ottenere un elenco di tutti i nodi beneith il nodo padre?

Per 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 questo ciclo di profondità è definito e sto solo diventando nodi, sepolto giù tre livelli. Quello che se la prossima volta che l’utente seleziona un nodo padre, ci sono sette livelli?

InformationsquelleAutor Matt Hanson | 2008-10-07



9 Replies
  1. 19

    Utilizzare 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
    • Basta una rapida modifica: Linea 3 dovrebbe chiamare GetAllChildren
    • Hanson]: corretta linea 3 commenti
    • Vorrei suggerire di non chiamare questo GetChildren come non solo i bambini (ad esempio i nodi direttamente sotto la corrente) si ottiene anche nipoti, pronipoti e così via. Per chiarezza trovo meglio avere GetDescendants per tutti i discendenti e GetChildren solo per il livello immediato seguito.
    • Ho cambiato così, invece di una lista di stringhe che ho fatto restituire il valore effettivo di Treenode, per un facile accesso in seguito. Grazie!
  2. 13

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

    function outputNodes(Node root)
        writeln(root.Text)
        foreach(Node n in root.ChildNodes)
            outputNodes(n)
        end
    end
    • questo frammento di codice mi ha insegnato funzione ricorsiva meglio del mio insegnante in un college.
  3. 13

    Ecco un frammento di codice che ho utilizzato per eseguire questa operazione dal mio core library.

    Permette di elencare i nodi di profondità prima o primo respiro, senza l’uso della ricorsione, che ha l’overhead di costruire stackframe in JIT motore. La sua molto veloce.

    Per utilizzarlo, è sufficiente andare:

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

    Scusa, hai un VB.Net tag; io non posso dare un esempio, ma sono sicuro che lavoreremo fuori.

    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;
        }
    }
    • Cercherò in. Grazie per la condivisione, Adrian!
    • Infine non ricorsiva approccio. Grazie mille.
  4. 12

    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 indicato da VB o convertiti.

  5. 3

    Adrian metodo è impressionante. Funziona molto veloce e ha funzionato meglio di quanto la ricorsione approccio. Ho fatto una traduzione di VB. Ho imparato molto da esso. Speriamo che qualcuno ancora ha bisogno.

    Per utilizzarlo, è sufficiente:

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

    Qui c’è il codice, EVVIVA! :

    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
  6. 2

    Ho convertito il codice per VB.Net con questo risultato:

    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
  7. 1
    nodParent As TreeNode
    'nodParent = your parent Node
    tvwOpt.Nodes.Find(nodParent.Name, True)

    Thats

    • BTW quello che è tvwOpt ?
  8. 1

    Se qualcuno ha ancora voglia di fare la ricorsione approccio, utilizzando Jop del codice, e talmente semplice mantenere aggiornati i nodi di struttura (in modo da poter usare il loro .tag .nome .controllato o .le proprietà del testo) 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
  9. 1

    Di solito ottenere un valore per un determinato nodo è interessante per i programmatori.Questo può essere ottenuto come segue.Si presuppone che si dispone di un controllo TextBox di nome texbox1 e un controllo TreeView denominato treeview1.In seguito dovrebbe restituire il valore di testo in corrispondenza dei nodi di livello 0.

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

Lascia un commento