2008-10-07 25 views
14

Tengo un control TreeView en mi aplicación WinForms .NET que tiene múltiples niveles de childnodes que tienen childnodes con más childnodes, sin profundidad definida. Cuando un usuario selecciona un nodo padre (no necesariamente en el nivel raíz), ¿cómo puedo obtener una lista de todos los nodos beneficiarios de ese nodo padre?Cómo obtener una lista de todos los nodos secundarios en TreeView en .NET

Por ejemplo, empecé con esto:

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 

El problema es que esta profundidad de bucle se define y yo sólo estoy poniendo nodos enterrado abajo de tres niveles. ¿Qué pasa si la próxima vez que el usuario selecciona un nodo padre, hay siete niveles?

Respuesta

17

Uso recursividad

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 
+0

Solo una edición rápida: la línea 3 debería llamar a GetAllChildren –

+0

@ [Matt Hanson]: línea 3 corregida según los comentarios –

+2

Sugeriría que no llame a esto 'GetChildren' ya que no solo obtiene hijos (es decir, nodos directamente debajo de la corriente uno) también tiene nietos, bisnietos, etc. Para mayor claridad, me parece mejor tener 'GetDescendants' para todos los descendientes y' GetChildren' para el nivel inmediatamente inferior. – Keith

12

se necesita una función recursiva para hacer esto [o un equivalente del bucle, pero la versión recursiva es más simple] - pseudocódigo:

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

este fragmento de código que me aprendió función recursiva mejor que mi profesor en la universidad. – Shahin

12

Aquí es un fragmento de código que utilizo para realizar esta tarea desde mi biblioteca central. Le permite hacer una lista de los nodos, ya sea en profundidad primero o aliento primero sin el uso de recurrencia, que tiene la sobrecarga de la construcción de fotogramas de pila en el motor de JIT. Es muy rápido.

Para usarlo, simplemente ir:

Lista < TreeNode> nodos = TreeViewUtils.FlattenDepth (árbol);

Lo siento, VB, no puedo dar un ejemplo, pero estoy seguro de que lo resolverá.

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

} 
+1

Lo investigaré. Gracias por compartir, Adrian! –

+0

Finalmente, un enfoque no recursivo. Muchas gracias. – ElektroStudios

1

Ik heb de código omgezet naar vb.net reunió DIT del 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 
12

tengo un método de extensión que utilizo para esto:

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

Es C#, pero podría ser referenciado desde VB o convertido a él.

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

Eso es todo

+0

BTW ¿Qué es tvwOpt? –

2

método de Adrian es impresionante. Funciona bastante rápido y funcionó mejor que el enfoque de recursión. He hecho una traducción a VB. Aprendí mucho de eso. Espero que alguien todavía lo necesite.

Para usarlo, simplemente:

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

Aquí está el código, ¡Salud! :

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 
0

Si alguien todavía quiere hacer el enfoque de la recursividad, utilizando el código de Jop, y manteniendo los TreeNodes (para que pueda utilizar su .tag, .name, .checked o propiedades .text) aquí está mi versión

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 
0

Normalmente, obtener un valor en el nodo especificado es interesante para los programadores. Esto se puede obtener de la siguiente manera.Se supone que tiene un texbox1 llamado control TextBox y un control TreeView llamado treeview1.Following devolvería el valor de texto a nivel de nodos 0.

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