Как получить список всех дочерних узлов в TreeView in.NET
У меня есть элемент управления TreeView в моем приложении WinForms .NET, который имеет несколько уровней childnodes, которые имеют childnodes с большим количеством childnodes, без определенной глубины. Когда пользователь выбирает любой родительский узел (не обязательно на корневом уровне), как я могу получить список всех узлов с этим родительским узлом?
например, я начал с этого:
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 ответов
использовать рекурсию
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
для этого нужна рекурсивная функция [или эквивалент цикла, но рекурсивная версия проще] - псевдокод:
function outputNodes(Node root)
writeln(root.Text)
foreach(Node n in root.ChildNodes)
outputNodes(n)
end
end
вот фрагмент кода, который я использую для выполнения этой задачи из моей основной библиотеки. Это позволяет перечислить узлы либо глубина сначала или дыхание первым без использования рекурсии, которая имеет накладные расходы на построение стековых кадров в JIT engine. Это очень быстро.
чтобы использовать его, просто идти:
List nodes = TreeViewUtils.FlattenDepth(дерево);
жаль, что вы VB головы, я не могу привести пример, но я уверен, что вы будете работать из.
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;
}
}
У меня есть метод расширения, которые я использую для этого:
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 или преобразовать в него.
метод Адриана это потрясающе. Работает довольно быстро и работает лучше, чем рекурсионный подход. Я сделал перевод на 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
ИК евр код omgezet НААР vb.net встретились дить АЛС 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
Если кто-то все еще хочет сделать подход рекурсии, используя код Jop и сохраняя TreeNodes (так что вы можете использовать их .имя тега. ,проверено или .свойства текста) вот моя версия
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
обычно получить значение на указанном узле интересно программистам.Это можно получить следующим образом.Предполагается, что элемент управления TextBox с именем texbox1 и элемент управления TreeView с именем treeview1.Following вернет значение text на уровне узлов 0.
textbox1.Text = treeview1.nodes(0).Text.ToString()