Tree
|
A-A1
-A2
|
B-B1
-B2
-B3
|
C-C1
-C2
private void treeView1_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
{
foreach (TreeNode tn in treeView1.Nodes)
{
if (!tn.Equals(e.Node) && tn.Text.ToUpper() == e.Label.ToUpper() )
{
MessageBox.Show("Name already available for parent. Cannot give same name.", "Rename element");
e.CancelEdit = true;
return;
}
}
string l_strOldDisplayName = treeView1.SelectedNode.Text;
this.BeginInvoke(new Action(() => RenameTreeElement(l_strOldDisplayName, e.Node)));
treeView1.LabelEdit = false;
treeView1.SelectedNode.EndEdit(false);
}
private void RenameElement(string f_strOldDisplayName, TreeNode updatedNode)
{
foreach (TreeNode currentNode in treeView1.Nodes)
{
if (currentNode.Level == 0)
{
if (updatedNode.Text == currentNode.Text)
{
MessageBox.Show("Name already available for parent. Cannot give same name.", "Rename element");
return;
}
}
}
}
I am renaming the tree node(A to B) at level 0 (A,B,C) but B is already present in treeview at that time i want to show message "Name already available for parent. Cannot give same name."
for that i have written above code but it is failed for when i give parent node name say 'A' to any child node in the tree it is not allowing..It should allow because parent name may be repeated in children
Updated code........
void treeView1_AfterLabelEdit(object sender, NodeLabelEditEventArgs e) {
foreach (TreeNode tn in treeView1.Nodes) {
if (!tn.Equals(e.Node) && tn.Text == e.Label&& !IsChildNodeHaveSameName(e.Label, e.Node)) {
MessageBox.Show("Name already in use.");
e.CancelEdit = true;
}
}
}
private bool IsChildNodeHaveSameName(string newName)
{//if new parent node name is under child node then skip
foreach (var node in Collect(treeView1.Nodes))
{
if (node.Text.ToUpper() == newName.ToUpper())
{
return true;
}
}
return false;
}
IEnumerable<TreeNode> Collect(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
yield return node;
foreach (var child in Collect(node.Nodes))
yield return child;
}
}
The e.Label property gives you the text that the user is writing in the floating label. With that, you can simplify your code into something like this:
void treeView1_AfterLabelEdit(object sender, NodeLabelEditEventArgs e) {
if (e.Node.Level == 0) {
foreach (TreeNode tn in treeView1.Nodes) {
if (!tn.Equals(e.Node) && tn.Text == e.Label) {
MessageBox.Show("Name already in use.");
e.CancelEdit = true;
}
}
}
}
Related
I want to traverse through a treeview & set the value property to be its position in the tree as shown below
A[val:1]->A1[val:11]
l l--->A2[val:12]
l----->A3[val:13]
B[val:2]->B1[val:21]
l l--->B2[val:22]
C[val:3]->C1[val:31]
l l--->C2[val:32]
I have written a recursive which returns me all the nodes but i am unable to assign the desired position to its nodes.
private void TraverseTreeNode(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
TraverseTreeNode(node.ChildNodes);
}
}
Considering that TreeNode.Value is of type string, this will, starting at level = 1:
private static void TraverseTreeNode(TreeNodeCollection nodes, int parentNumber)
{
var childNumber = 1;
foreach (TreeNode node in nodes)
{
node.Value = string.Format("{0}{1}", parentNumber, childNumber ).Substring(0,node.Depth+1);
TraverseTreeNode(node.ChildNodes, parentNumber);
childNumber++;
if (node.Depth == 0) { parentNumber++; }
}
}
Only works for two levels but is easily extendable by adding additional parameters to TraverseTreeNode.
UPDATE
The following will work for any depth in hierarchy:
private static void TraverseTreeNode(TreeNodeCollection nodes, int parentNumber)
{
var childNumber = 1;
foreach (TreeNode node in nodes)
{
node.Value = node.Parent != null && node.Parent.Value != null
? string.Format("{0}{1}", node.Parent.Value, childNumber)
: string.Format("{0}{1}", parentNumber, childNumber).Substring(0, node.Depth + 1);
TraverseTreeNode(node.ChildNodes, parentNumber);
childNumber++;
if (node.Depth == 0) { parentNumber++; }
}
}
As you need recursive method, try this
private void Caller()
{
TraverseTreeNode(treeView1.Nodes);
}
private void TraverseTreeNode(TreeNodeCollection nodes)
{
int index = 1;
foreach (TreeNode node in nodes)
{
node.Text = (node.Parent != null ? node.Parent.Text : string.Empty) + index++;
TraverseTreeNode(node.Nodes);
}
}
I'm working on a Winform application, how can I check if there is a treeNode that its text is inside string Mystring? And how can i retrieve the tag of this node please?
if (myString.Contains(treeView1.Nodes.ToString()))
This works for only first matched node.
private TreeNode FindMatchedNode(TreeNodeCollection tnCol, string text)
{
TreeNode tn = null;
foreach (TreeNode node in tnCol)
{
if (text.ToLower().Contains(node.Text.ToLower()))
{
tn = node;
break;
}
else if (node.Nodes != null)
{
tn = FindNode(node.Nodes, text);
if (tn != null)
break;
}
}
return tn;
}
and for all matched nodes
private List<TreeNode> FindAllMatchedNodes(TreeNodeCollection tnCol, string text)
{
List<TreeNode> retVal = new List<TreeNode>();
foreach (TreeNode node in tnCol)
{
if (text.ToLower().Contains(node.Text.ToLower()))
{
retVal.Add(node);
}
else if (node.Nodes != null)
{
retVal.AddRange(FindNode(node.Nodes, text));
}
}
return retVal;
}
This method will traverse tree from root and find first node that Text is inside of myString
public object FindNode()
{
var queue = new Queue<TreeNode>();
foreach (var n in treeView1.Nodes)
{
// Add all root nodes to queue
queue.Enqueue(n);
}
while (queue.Count > 0)
{
// Take the next node from the front of the queue
var node = queue.Dequeue();
// Check if myString contains node text
if (myString.Contains(node.Text))
return node.Tag;
// Add the node’s children to the back of the queue
foreach (var child in node.Children)
{
queue.Enqueue(child);
}
}
// None of the nodes matched the specified string.
return null;
}
I need to expand my treeview based on a fullpath in c#
My tree view has 2 nodes which are collapsed and I want to expand Node A to number 3
so I have the fullpath of node A\1\2\3.
How can I step through and open each node based of the fullpath? Also the length of the fullpath may change, so i may need to open node be to level 6. So it needs to be done based on the fullpath. Any help would be great.
Node A
1
2
3
Node B
1
2
3
4 5 6
This is what I've tried:
TreeNode [] n= treeView1.Nodes.Find(search, true);
if (n.Length > 0)
found = true;
treeView1.Nodes[t].Collapse();
foreach (TreeNode p in n) {
string[] a = p.FullPath.Split('\\');
foreach (string b in a) {
treeView1.SelectedNode = treeView1.Nodes[b];
treeView1.SelectedNode.Expand();
I'm sorry for not commenting on above answer given by S3ddi9 which is CORRECT. I'm only adding something.
So the answer given by S3ddi9
...
string path = #"A\1\2\";
var path_list = path.Split('\\').ToList();
foreach (TreeNode node in treeView1.Nodes)
if (node.Text == path_list[0])
ExpandMyLitleBoys(node, path_list);
}
private void ExpandMyLitleBoys(TreeNode node, List<string> path)
{
path.RemoveAt(0);
node.Expand();
if (path.Count == 0)
return;
foreach (TreeNode mynode in node.Nodes)
if (mynode.Text == path[0])
{
ExpandMyLitleBoys(mynode, path); //recursive call
break; //this was missing in earlier answer
}
}
Does work, BUT you must add a BREAK (I marked it), because if the for loop doesn't finish, return; won't return you to your main function and it will throw you an exception because path[0] is null.
I hope this will be more simpler, for Treeviews the best approach is to use recursive methods
...
string path = #"A\1\2\";
var path_list = path.Split('\\').ToList();
foreach (TreeNode node in treeView1.Nodes)
if (node.Text == path_list[0])
ExpandMyLitleBoys(node, path_list);
}
private void ExpandMyLitleBoys(TreeNode node, List<string> path)
{
path.RemoveAt(0);
node.Expand();
if (path.Count == 0)
return;
foreach (TreeNode mynode in node.Nodes)
if (mynode.Text == path[0])
ExpandMyLitleBoys(mynode, path); //recursive call
}
this does the work perfectly
Cracked it!!
TreeNode[] n = treeView1.Nodes.Find(search, true);
if (n.Length > 0)
found = true;
treeView1.Nodes[t].Collapse();
foreach (TreeNode p in n)
{
i = 0;
string[] a = p.FullPath.Split('\\');
foreach (string b in a)
{
if (i == 0)
{
treeView1.SelectedNode = treeView1.Nodes[b];
current = treeView1.Nodes[b];
treeView1.SelectedNode.Expand();
i = 1;
}
else
{
treeView1.SelectedNode = current.Nodes[b];
current = current.Nodes[b];
treeView1.SelectedNode.Expand();
if (b.ToUpper().Contains(search))
{
treeView1.SelectedNode.BackColor = System.Drawing.Color.Red;
}
I wrote a little simpler routine that works great. no recursion at all...
This assumes your path is a full file path like... "C:\program files\myapp" and when you add your nodes you set the node Key equal to the folder name
string[] strFolders = strPath.Split('\'));
System.Windows.Forms.TreeNode CurrentNode = null;
System.Windows.Forms.TreeNode[] FoundNodes = null;
foreach (string folder in strFolders) {
if (!folder.Contains(":")) {
if (CurrentNode == null) {
FoundNodes = treeFolders.Nodes.Find(folder, false);
} else {
FoundNodes = CurrentNode.Nodes.Find(folder, false);
}
if (FoundNodes.Length > 0) {
CurrentNode = FoundNodes[0];
CurrentNode.Expand();
} else {
//no folder found. cant continue
break;
}
}
}
if (CurrentNode != null) {
treeFolders.SelectedNode = CurrentNode;
}
i got this tree view and i made it to select all children if parent is checked, the way back as well. There's another rule to check some dependent child too. The problem is: I want to check the parent if any child is checked, but because those other rules i can't find a way to do that without the rules get conflict. So here's is the code i've made until now:
private void tvMorgan_AfterCheck(object sender, TreeViewEventArgs e)
{
//Check Children if parent checked
if (e.Node.Nodes.Count > 0)
{
TreeNode tnParent = e.Node;
if (tnParent.Checked)
{
foreach (TreeNode tnChild in tnParent.Nodes)
{
tnChild.Checked = true;
}
}
//Unchecked children if parent unchecked
else
{
foreach (TreeNode tnChild in tnParent.Nodes)
{
tnChild.Checked = false;
}
}
}
//If dependent node is selected, check the other two
else if (((e.Node.Text.Contains("BRL/EUR")) && (e.Node.Checked)) && (e.Node.Parent.Text.Contains("FWD")))
{
TreeNode tnParent = e.Node.Parent;
foreach (TreeNode tn in tnParent.Nodes)
{
if (tn.Text.Contains("BRL/USD") || tn.Text.Contains("EUR/USD"))
tn.Checked = true;
}
}
//If one of the two necessary nodes are uncheked, then uncheck the dependent one
else if ((((e.Node.Text.Contains("BRL/USD")) || (e.Node.Text.Contains("EUR/USD"))) && (!e.Node.Checked)) && (e.Node.Parent.Text.Contains("FWD")))
{
TreeNode tnParent = e.Node.Parent;
foreach (TreeNode tn in tnParent.Nodes)
{
if (tn.Text.Contains("BRL/EUR"))
tn.Checked = false;
}
}
}
Thanks in advance
The documentation of the TreeView.AfterCheck Event shows exactly how to do what you are looking for
I want to show all children of the first level on the treeview by default.
And then expand all children of those on click.
Try:
foreach (TreeNode tn in treeView1.Nodes) {
tn.Expand();
}
When adding nodes during runtime, you can just check the level and expand, if needed:
private void ShouldAutoExpand(TreeNode tn) {
if (tn.Level == 0)
tn.Expand();
}
There is no NodeAdded event you can hook into to check that automatically. You would have to determine yourself whether or not a node should be expanded "by default".
Update:
From your comment, it seems like you want to have all level 0 nodes expanded, but then expand all child nodes of level 1 when you expand them.
Try subscribing to the BeforeExpand event with this code:
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e) {
treeView1.BeforeExpand -= treeView1_BeforeExpand;
if (e.Node.Level == 1) {
e.Node.ExpandAll();
}
treeView1.BeforeExpand += treeView1_BeforeExpand;
}
you can try something like this.. you will have to change the example to fit your own code since you neglected to paste any code that you have or attempted
private void addChildNode_Click(object sender, EventArgs e)
{
var childNode = textBox1.Text.Trim();
if (!string.IsNullOrEmpty(childNode)) {
TreeNode parentNode = treeView2.SelectedNode ?? treeView2.Nodes[0];
if (parentNode != null) {
parentNode.Nodes.Add(childNode);
treeView2.ExpandAll();
}
}
}
if you want a recursive, try this:
void expAll(TreeNode node)
{
node.Expand();
foreach(TreeNode i in node.Nodes)
{
expAll(i);
}
}
private TreeNode ExpandUptoLevel(TreeNode tn,int level)
{
if (level != 0)
{
level --;
tn.Nodes[0].Expand();
return ExpandUptoLevel(tn.FirstNode, level);
}
return tn;
}
To expand all nodes in a tree to a level the above code does not work. Just add a check to read and compare the actual node level to the level that you wish to expand to. Here's a code snippet.
private void ExpandUptoLevel(TreeNode tn, int level)
{
if (level >= tn.Level)
{
tn.Expand();
foreach (TreeNode i in tn.Nodes)
{
ExpandUptoLevel(i,level);
}
}
}
Only to open the first nodes:
for (int i = 0; i< treeView1.Nodes.Count; i++)
{
treeView1.Nodes[i].Expand();
}