I have a TreeView control in my WinForms .NET application that has multiple levels of childnodes that have childnodes with more childnodes, with no defined depth. When a user selects any parent node (not necessarily at the root level), how can I get a list of all the nodes beneith that parent node?
For example, I started off with this:
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
The problem is that this loop depth is defined and I'm only getting nodes burried down three levels. What if next time the user selects a parent node, there are seven levels?
Use the FindNode method to get a node from the TreeView control at the specified value path. The value path contains a delimiter-separated list of node values that form a path from the root node to the current node. Each node stores its value path in the ValuePath property.
For setting the selected node in a TreeView you call TreeView. SelectedNode to the TreeNode you want to select. then it should select the node you just created.
Solution 1 Use TreeView. SelectedNode[^] property, which get or set selected node for currently selected Treeview. If no TreeNode is currently selected, the SelectedNode property is a null reference (Nothing in Visual Basic).
Use recursion
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
you need a recursive function to do this [or a loop equivalent, but the recursive version is simpler] - pseudocode:
function outputNodes(Node root)
writeln(root.Text)
foreach(Node n in root.ChildNodes)
outputNodes(n)
end
end
I have an extension method that I use for this:
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;
}
}
It's C#, but could be referenced from VB or converted to it.
Here is a snippet of code that I use to perform this task from my core library.
It allows you to list the nodes either depth first or breath first without the use of recursion, which has the overhead of constructing stackframes in the JIT engine. Its very fast.
To use it simply go:
List< TreeNode > nodes = TreeViewUtils.FlattenDepth(tree);
Sorry, you have a VB.Net tag; I can't give an example, but I'm sure you'll work it out.
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;
}
}
nodParent As TreeNode
'nodParent = your parent Node
tvwOpt.Nodes.Find(nodParent.Name, True)
Thats it
Adrian's method it's awesome. Works quite fast and worked better than the recursion approach. I've done a translation to VB. I've learned a lot from it. Hopefully someone still needs it.
To use it simply:
Dim FlattenedNodes As List(Of TreeNode) = clTreeUtil.FlattenDepth(Me.TreeView1)
Here is the code, 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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With