How to search child nods in a treeview - c#

I tride it in this way,
private void btnFind_Click(object sender, EventArgs
{
for (int i = 0; i < treeView1.Nodes.Count - 1; i++)
{
MessageBox.Show(i.ToString());
treeView1.Nodes[i].BackColor = Color.Empty;
}
var result = from TreeNode node in treeView1.Nodes
where node.Text.Contains( Convert.ToString(txtFind.Text))
select node.Index;
foreach (int search in result)
{
treeView1.Nodes[search].BackColor = Color.Yellow;
}
}
But in this way I can find only parent nodes. Is there a proper way to do this

You can have a method to process the TreeView and then another to recursively call the child nodes. This will load _matchingNodes with all of the nodes that match your text.
Private List<TreeNode> _matchingNodes;
// Process the TreeView.
private void ProcessTreeView(TreeView treeView, String FindText)
{
_matchingNodes = new List<TreeNode>();
// Process each node recursively.
foreach (TreeNode n in treeView.Nodes)
{
if(n.Text.Contains(FindText))
_matchingNodes.Add(n);
ProcessRecursive(n, FindText);
}
}
private void ProcessRecursive(TreeNode treeNode, String FindText)
{
// Process each node recursively.
foreach (TreeNode n in treeNode.Nodes)
{
if(n.Text.Contains(FindText))
_matchingNodes.Add(n);
ProcessRecursive(n, FindText);
}
}

private void btnFind_Click(object sender, EventArgs e)
{
CallRecursive(treeView1);
}
private void PrintRecursive(TreeNode treeNode)
{
if (treeNode.Text.Contains(txtFind.Text.ToString()))
{
//MessageBox.Show(treeNode.Text);
treeNode.BackColor = Color.Blue;
}
else
{
treeNode.BackColor = Color.Empty;
}
// Print each node recursively.
foreach (TreeNode tn in treeNode.Nodes)
{
PrintRecursive(tn);
}
}
// Call the procedure using the TreeView.
private void CallRecursive(TreeView treeView)
{
// Print each node recursively.
TreeNodeCollection nodes = treeView.Nodes;
foreach (TreeNode n in nodes)
{
PrintRecursive(n);
}
}
I solved It Like this and it works as expected.

TreeView.nodes.find(nodeName,1)
The numeral 1 specifies to look at all child nodes too. A 0 means say to not include children. Only tested in Powershell.
Perhaps not so helpful for searching the text of the nodes but hopefully you can obtain the node name.

Related

TreeView checking/unchecking descendants - sometimes only root is affected

Consider a TreeView structure such as the following:
The goal is to have a node's descendants check or uncheck themselves accordingly when a particular node is checked. For example, in the above, if "D" is unchecked, "D A", "D A A" and "D A B" should uncheck themselves.
Currently, the code being used is as follows:
private void treeView_AfterCheck(object sender, TreeViewEventArgs e)
{
if (e.Action != TreeViewAction.Unknown)
{
if (e.Node.Checked)
{
checkChildNodes(e.Node.Nodes);
}
else
{
uncheckChildNodes(e.Node.Nodes);
}
}
}
private void checkChildNodes(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
node.Checked = true;
if (node.Nodes.Count>0)
checkChildNodes(node.Nodes);
}
}
private void uncheckChildNodes(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
node.Checked = false;
if (node.Nodes.Count>0)
uncheckChildNodes(node.Nodes);
}
}
The problem with this is that sometimes the checking/unchecking of descendants does not occur, when the "root" node is clicked very fast. How can this be solved?
What has also been tried, is using the BeforeCheck event, as per the following link: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.treeview.aftercheck?view=netcore-3.1

Count nodes with and without subsequent child nodes

I am trying to count number of tree nodes with (A) and without subsequent child nodes (B). For example the image below should return 2/1.
I tried to play around with TreeView methods but cant figure out how to work with deeper level nodes.
private void tvResources_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
int a=0,b=0;
foreach (TreeNode node in e.Node.Nodes)
{
if (e.Node.Nodes.Contains(node))
a += 1;
else
b += 1;
}
e.Node.Text += #" - " + a+"/"+b;
}
This can probably be done with some recursive function, but is there any easier solution?
If you need just the current node (before expanding), you could just use the foreach loop to check the number of nodes for each direct child and that will give you the answer directly.
private void tvResources_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
CalculateAB( e.Node );
}
private void CalculateAB( TreeNode node )
{
int a = 0;
int b = 0;
foreach ( TreeNode child in node.Nodes )
{
if ( child.Nodes.Count() > 0 )
{
a++;
}
else
{
b++;
}
}
node.Text += #" - " + a + "/" + b;
}
You can then use recursion if you want to calculate the values for the whole TreeView at once. You can use depth-first search and calculate the a/b values of all nodes you encounter using the CalculateAB method.
private void CalculateForTree( TreeNode root )
{
foreach ( var child in root.Nodes )
{
CalculateForTree( child );
}
CalcualteAB( root );
}

Update Treeview with new filepath

I have an Observable collection of Paths.
The thing I want to do is to update my treeView on collection changed.
Could you please help me with creating method that takes Treeview, FilePath and PathSeparator as parameters and adding new node to my treeView. This is what i have now:
private void MyCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
TreeViewAddNode(TreeView,Path,PathSeparator)
}
TreeViewAddNode(TreeView treeView, string path, char pathSeparator)
{
foreach (string subPath in path.Split(pathSeparator))
{
//Hear should be logic to add new nodes if they don't exist }
}
}
As the Result I wanna have something like that:
C:
--Temp
----File1.txt
----File2.txt
----New Foledr
-------File3.txt
--AnotherFolder
----File4.txt
D:
--New Folder
----File.txt
EDIT
Now with better understanding on what is being asked:
private void TreeViewAddNode(TreeView treeView, string path, char pathSeparator)
{
string[] split = path.Split(pathSeparator);
for(int i = 0; i < split.Length; i++)
{
if(i == 0)
{
checkTreeView(treeView, split[0]);
}
else
{
TreeNode node = treeView1.Nodes.Find(split[i - 1], true)[0];
checkNodes(node, split[i]);
}
}
}
private void checkTreeView(TreeView treeView, string path)
{
bool exists = false;
foreach(TreeNode node in treeView.Nodes)
{
if(node.Text == path)
{
exists = true;
}
}
if(!exists)
{
TreeNode node = treeView.Nodes.Add(path);
node.Name = path;
}
}
private void checkNodes(TreeNode parent, string path)
{
bool exists = false;
foreach(TreeNode node in parent.Nodes)
{
if(node.Text == path)
{
exists = true;
}
}
if(!exists)
{
TreeNode node = parent.Nodes.Add(path);
node.Name = path;
}
}
checkTreeView checks if the path is allready present in the treeview nodes. if it isn't add it to the treeview. Same goes for checkNodes.

Is there a method for searching for TreeNode.Text field in TreeView.Nodes collection?

Like this:
TreeNode[] treeNodes = treeView.Nodes.Find(searchString, true);
but I want it to search in the text field instead of the name field.
I am not aware of any inbuilt method but you may use LINQ
TreeNode[] treeNodes = treeView.Nodes
.Cast<TreeNode>()
.Where(r => r.Text == "yourText")
.ToArray();
To search all tree nodes (not only the direct child nodes) you can use the extension method below
var nodes = treeView1.FlattenTree()
.Where(n => n.Text == "sometext")
.ToList();
--
public static class SOExtension
{
public static IEnumerable<TreeNode> FlattenTree(this TreeView tv)
{
return FlattenTree(tv.Nodes);
}
public static IEnumerable<TreeNode> FlattenTree(this TreeNodeCollection coll)
{
return coll.Cast<TreeNode>()
.Concat(coll.Cast<TreeNode>()
.SelectMany(x => FlattenTree(x.Nodes)));
}
}
If I understand you correctly (you last question was very confusing), you can write a find method yourself as follows
public static TreeNode[] Find(this TreeNode motherNode, string findNodeText)
{
List<TreeNode> nodeList = new List<TreeNode>();
foreach (TreeNode childNode in motherNode.Nodes)
if (childNode.Text.Equals(findNodeText, StringComparison.CurrentCulture))
nodeList.Add(childNode);
return nodeList.ToArray<TreeNode>();
}
This method can be used like
TreeView myTreeView = new TreeView();
foreach (TreeNode node in myTreeView.Nodes)
{
TreeNode[] childNodes = node.Find("Text");
// Do something...
}
I hope this helps.
The following code only shows the nodes which matches the search criteria.
Copy the following code in the search event
private void tbxSearch_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
trvMenu.BeginUpdate();
if (tbxSearch.Text.Length > 0)
{
for (int i = trvMenu.Nodes.Count; i > 0 ; i--)
{
NodeFiltering(trvMenu.Nodes[i - 1], tbxSearch.Text);
}
}
trvMenu.EndUpdate();
}
Then create the serch & filter function
private bool NodeFiltering(TreeNode Nodo,string Texto)
{
bool resultado = false;
if (Nodo.Nodes.Count == 0)
{
if (Nodo.Text.ToUpper().Contains(Texto.ToUpper()))
{
resultado = true;
}
else
{
Nodo.Remove();
}
}
else
{
for (int i = Nodo.Nodes.Count; i > 0; i--)
{
if (NodeFiltering(Nodo.Nodes[i - 1], Texto))
resultado = true;
}
if (!resultado)
Nodo.Remove();
}
return resultado;
}
This code is pretty nice for creating Treeview menus with many levels.

How can I find a root node in TreeView

I have a TreeView in my Windows application. Tn this TreeView, the user can add some root nodes and also some sub nodes for these root nodes and also some sub nodes for these sub nodes and so on ...
For example:
Root1
A
B
C
D
E
Root2
F
G
.
.
.
Now my question is that if I am at node 'E' what is the best way to find its first root node ('Root1')?
Here is a little method for you:
private TreeNode FindRootNode(TreeNode treeNode)
{
while (treeNode.Parent != null)
{
treeNode = treeNode.Parent;
}
return treeNode;
}
you can call in your code like this:
var rootNode = FindRootNode(currentTreeNode);
public TreeNode RootTreeNode(TreeNode n) { while (n.Level > 0) { n = n.Parent; } return n; }
Example to get root treenode:
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
var node = (e == null ? ((System.Windows.Forms.TreeView)sender).SelectedNode : e.Node);
var rootNode = RootTreeNode(node);
}
Enjoy

Categories

Resources