Delete checked node in a Tree view c# - c#

I have a tree with multiple nodes with different depth.
So I need to use the check boxes for deleting nodes not the selection method.

I have tried this code and it worked good,
if anyone have a comment please come up with it.
ArrayList checkedNodes = new ArrayList();
if (elementsHierTree.CheckedNodes.Count != 0)
{
foreach (TreeNode nodee in elementsHierTree.CheckedNodes)
{
if (nodee.Parent != null)
{
checkedNodes.Add(nodee);
}
}
}
foreach (TreeNode chNode in checkedNodes)
{
chNode.Parent.ChildNodes.Remove(chNode);
}

Related

C# - XML Validation with XSD - Presenting results in Listbox and Treeview

Hello all!
I have the following use case:
My Winform-App is validating a prarticular XML against the XSD and displays the errors (if any) in a listbox (this works fine). In addition to that I load the validated XML into a treeview.
Now, what I would like to achieve is to give the user the ability to doubleklick the error in the listbox to have then the treeview selecting the relevant element which caused the error.
I'm a little stuck with this actually. I now the row number of the error, but I can't select the relevant node in the treeview by using the row number.
Does anybody have an idea how I can achieve this?
Any hint is very much appreciated :)
kind regards
UPDATE:
Code filling the treeview:
doc.Load(XMLDocPath);
XmlNodeTree root = new XmlNodeTree(0, doc.LastChild);
treeDGUXml.Nodes.Add(root);
FillTreeView(root.Nodes, doc.LastChild.ChildNodes);
And the method:
private void FillTreeView(TreeNodeCollection c, XmlNodeList l)
{
if (l == null)
{
return;
}
foreach (XmlNode e in l)
{
XmlNodeTree n = new XmlNodeTree(nRow, e);
c.Add(n);
FillTreeView(n.Nodes, e.ChildNodes);
}
And the Class:
public class XmlNodeTree : TreeNode
{
private XmlNode mNode;
public XmlNode Node
{
get { return mNode; }
}
public XmlNodeTree(int rownumber, XmlNode node)
{
mNode = node;
if (node.NodeType == XmlNodeType.Text)
{
Text = node.InnerText;
}
else
{
Text = rownumber.ToString() + " - " + node.Name;
nRow++;
}
if (node.Attributes != null)
{
foreach (XmlAttribute a in node.Attributes)
{
Text += " " + a.OuterXml;
}
}
}
}
Thank you very much for the hints. I decided to have another approach without treeview. I load the XML into a richtext box with appropriate coloring. This way I can select the relevant text. The user cannot collapse the xml structure, but this now is better than nothing ;) Thank you anyway for your suggestions! –

Clearing TreeView item ChildNodes also clears Parent reference?

I'm developing an ASP.NET 4.0 web application and I am using a TreeView control. I have one problem that I really can't understand why this is happening. I have checkboxes associated with the tree items.
If the checkbox is not checked everything works just fine, but when I execute the following line:
node.ChildNodes.Clear();
If the checkbox is checked for the node, the node.Parent is null after the Clear(). If it is not checked, parent is still correct. I really can't understand why the clearing of the childnodes collection will also clear my parent reference. I actually don't use or modify the checked property within this call. I am also 100% sure that my parent isn't a child to my node as well (why would it differ if it checked or not).
The workaround I need to use in order for the code to work as expected is:
TreeNode[] checkedNodes = new TreeNode[tvResults.CheckedNodes.Count];
tvResults.CheckedNodes.CopyTo(checkedNodes, 0);
foreach (TreeNode checkedNode in checkedNodes) // Uncheck all nodes temporary.
checkedNode.Checked = false;
node.ChildNodes.Clear(); // Now it is ok to clear and parent is "saved".
foreach (TreeNode checkedNode in checkedNodes) // Recheck all checked nodes again.
checkedNode.Checked = true;
Any idea anyone about this issue?
Thanks,
Mattias
PS! Please be kind, this is my first question ever...
Below is the code from ASP.NET TreeNodeCollection.Clear (from .NET 4.5). As you can see, it does clear all checked nodes without performing any validation. So this is by design (rather a bug by design) and not a bug in your code. My advice would be add an extension method that performs the workaround you listed in the question so that you can easily reuse it.
// System.Web.UI.WebControls.TreeNodeCollection
/// <summary>Empties the <see cref="T:System.Web.UI.WebControls.TreeNodeCollection" /> object.</summary>
public void Clear()
{
if (this.Count == 0)
{
return;
}
if (this._owner != null)
{
TreeView owner = this._owner.Owner;
if (owner != null)
{
if (owner.CheckedNodes.Count != 0)
{
owner.CheckedNodes.Clear();
}
for (TreeNode treeNode = owner.SelectedNode; treeNode != null; treeNode = treeNode.Parent)
{
if (this.Contains(treeNode))
{
owner.SetSelectedNode(null);
break;
}
}
}
}
foreach (TreeNode current in this._list)
{
current.SetParent(null);
}
this._list.Clear();
this._version++;
if (this._isTrackingViewState)
{
this.Log.Clear();
}
this.Log.Add(new TreeNodeCollection.LogItem(TreeNodeCollection.LogItemType.Clear, 0, this._isTrackingViewState));
}

Copy all Selected (Checked) TreeNodes from one treeview to another (include unchecked parents) C#

I've created a directory and file browser TreeView on the left side. I want the users to be able to browse the tree and check the files and directories that they would like to move to another treeview.
The other TreeView is a user control I found online called TreeViewColumn. I will be using that control to allow the user to add other data (categories, attributes) to the files and folders selected.
The trouble I'm running into is two-fold, I need to recursively add all children (I can figure this out) but I need to add unchecked parents to checked children (to preserve the hierarchy).
private void IterateTreeNodes(TreeNode originalNode, TreeNode rootNode)
{
//Take the node passed through and loop through all children
foreach (TreeNode childNode in originalNode.Nodes)
{
// Create a new instance of the node, will need to add it to the recursion as a root item
// AND if checked it needs to get added to the new TreeView.
TreeNode newNode = new TreeNode(childNode.Text);
newNode.Tag = childNode.Tag;
newNode.Name = childNode.Name;
newNode.Checked = childNode.Checked;
if (childNode.Checked)
{
// Now we know this is checked, but what if the parent of this item was NOT checked.
//We need to head back up the tree to find the first parent that exists in the tree and add the hierarchy.
if (tvSelectedItems.TreeView.Nodes.ContainsKey(rootNode.Name)) // Means the parent exist?
{
tvSelectedItems.TreeView.SelectedNode = rootNode;
tvSelectedItems.TreeView.SelectedNode.Nodes.Add(newNode);
}
else
{
AddParents(childNode);
// Find the parent(s) and add them to the tree with their CheckState matching the original node's state
// When all parents have been added, add the current item.
}
}
IterateTreeNodes(childNode, newNode);
}
}
private TreeNode AddParents(TreeNode node)
{
if (node.Parent != null)
{
//tvDirectory.Nodes.Find(node.Name, false);
}
return null;
}
Could anyone help with this code so that it recursively adds checked nodes (and their parent, regardless of checked state). I need to maintain directory hierarchy.
Thanks for any help!
A rather (not-so-clean and not-preferred) solution could be to clone the tree first, and then remove unchecked branches.
Else, when you are adding a node, write a recursive method to traverse through node's parent node until you hit the root. And simply optimize it by checking if childNode.parent already exists, just ignore the branch and move on. i.e. Backtrack to root node.
I got it working. I was already aware of what #Yahya was saying, I was hoping for an easier way / better approach.
The code below is certainly not optimal, I will continue improving it on my end but at this point it is looking through a treeview on the left and copying all of the checked items (and their parents - regardless of CheckedState) to a treeview on the right.
Hopefully this helps someone and thanks for answering #Yahya.
I'm open to improvements but keep in mind this is a one-time use utility.
private void cmdMoveRight_Click(object sender, EventArgs e)
{
tvSelectedItems.TreeView.Nodes.Clear();
// Traverse first level Tree Nodes
foreach (TreeNode originalNode in tvDirectory.Nodes)
{
TreeNode newNode = new TreeNode(originalNode.Text);
newNode.Name = originalNode.Name;
newNode.Tag = originalNode.Tag;
newNode.Checked = originalNode.Checked;
//Only add to the new treeview if the node is checked
if (originalNode.Checked)
{
tvSelectedItems.TreeView.Nodes.Find(originalNode.Parent.Name,true)[0].Nodes.Add(newNode);
}
//Start recursion - this will be called for each first level node - there should technically only be 1 "ROOT" node.
IterateTreeNodes(originalNode, newNode);
}
}
private void IterateTreeNodes(TreeNode originalNode, TreeNode rootNode)
{
//Take the node passed through and loop through all children
foreach (TreeNode childNode in originalNode.Nodes)
{
// Create a new instance of the node, will need to add it to the recursion as a root item
// AND if checked it needs to get added to the new TreeView.
TreeNode newNode = new TreeNode(childNode.Text);
newNode.Tag = childNode.Tag;
newNode.Name = childNode.Name;
newNode.Checked = childNode.Checked;
if (childNode.Checked)
{
// Now we know this is checked, but what if the parent of this item was NOT checked.
//We need to head back up the tree to find the first parent that exists in the tree and add the hierarchy.
TreeNode[] nodestest = tvSelectedItems.TreeView.Nodes.Find(childNode.Parent.Name, true);
if (nodestest.Length > 0)
{
tvSelectedItems.TreeView.Nodes.Find(childNode.Parent.Name,true)[0].Nodes.Add(newNode);
}
else
{
AddParents(childNode);// Find the parent(s) and add them to the tree with their CheckState matching the original node's state
}
}
//recurse
IterateTreeNodes(childNode, newNode);
}
}
private void AddParents(TreeNode node)
{
if (node.Parent != null)// Check if parent is null (would mean we're looking at the root item
{
TreeNode[] nodestest = tvSelectedItems.TreeView.Nodes.Find(node.Parent.Name, true);
if (nodestest.Length > 0)
{
TreeNode[] nodes = tvDirectory.Nodes.Find(node.Name, true);
TreeNode newNode = new TreeNode(nodes[0].Text);
newNode.Name = nodes[0].Name;
newNode.Tag = nodes[0].Tag;
newNode.Checked = nodes[0].Checked;
tvSelectedItems.TreeView.Nodes[node.Parent.Name].Nodes.Add(newNode);
}
else
{
AddParents(node.Parent);
TreeNode newNode = new TreeNode(node.Text);
newNode.Name = node.Name;
newNode.Tag = node.Tag;
newNode.Checked = node.Checked;
tvSelectedItems.TreeView.Nodes.Find(node.Parent.Name,true)[0].Nodes.Add(newNode);
}
}
else // deal with root node
{
TreeNode rootNode = new TreeNode(node.Text);
rootNode.Name = node.Name;
rootNode.Tag = node.Tag;
rootNode.Checked = node.Checked;
tvSelectedItems.TreeView.Nodes.Add(rootNode);
}
}

c# asp.net treeview - all properties working except TEXT

when my page opens it runs this method:
private void PrintRecursive(TreeNode treeNode, string problemValue)
{
// Print the node.
System.Diagnostics.Debug.WriteLine(treeNode.Text);
if (treeNode.Value == problemValue.Split(':')[0])
{
treeNode.Checked = true;
// Then expand the SelectedNode and ALL its parents until no parent found
treeNode.Expand();
while (treeNode.Parent != null)
{
treeNode = treeNode.Parent;
treeNode.Expand();
}
if (problemValue.Contains(":"))
treeNode.Text += problemValue.Split(':')[1];
return;
}
// Print each node recursively.
foreach (TreeNode tn in treeNode.ChildNodes)
{
PrintRecursive(tn, problemValue);
}
}
treeNode.Checked = true works fine!
treeNode.Expand() work great!
however treeNode.Text += problemValue.Split(':')[1]; does nothing!
the value of problemValue is "111:someproblem"
what am i doing wrong?
You need to move
if (problemValue.Contains(":"))
treeNode.Text += problemValue.Split(':')[1];
above the while statement.
The problem is that while you are expanding the parents, you are updating the value of treeNode, so when you try to set the text of treeNode, you are actually at one of the parent nodes.
If you are wanting to see how to do this check out this previous StackOverFlow Posting as well for additional ideas on how to Enumerate TreeNodes Implementing IEnumerable
if you are wanting to print TreeNodes Recursively look at this example
private void PrintRecursive(TreeNode treeNode)
{
// Print the node.
System.Diagnostics.Debug.WriteLine(treeNode.Text);
MessageBox.Show(treeNode.Text);
// 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);
}
}
If you want to do this as IEmumerable try the following below
public static class Extensions
{
public static IEnumerable<T> GetRecursively<T>(this IEnumerable collection,
Func<T, IEnumerable> selector)
{
foreach (var item in collection.OfType<T>())
{
yield return item;
IEnumerable<T> children = selector(item).GetRecursively(selector);
foreach (var child in children)
{
yield return child;
}
}
}
}
Here's an example of how to use it
TreeView view = new TreeView();
// ...
IEnumerable<TreeNode> nodes = view.Nodes.
.GetRecursively<TreeNode>(item => item.Nodes);

How do I loop through all layers of Treeview nodes?

Read EDIT 2 first
I am trying to set up some way to visually distinguish the nodes in a winform app. For example, alternating colors.
Can some one start me down that path? Also, has anyone else had to do that before and how did you do it?
Thanks
EDIT
I had seen the backcolor setting as well(Thank You) but I am having trouble getting it to work. I do not see a Paint() event for treeviews. I tried putting the below code in my Form Load() but it isn't working. Possibly because the treeview is loaded yet??
private void frmCaseNotes_Load(object sender, System.EventArgs e)
{
foreach (TreeNode treeNode in treeView1.Nodes[0].Nodes)
{
treeNode.BackColor = Color.DeepSkyBlue;
}
}
EDIT 2
Okay, I have the initial problem out of the way using the below on Form_Load()
foreach (TreeNode treeNode in treeView1.Nodes)
{
if (treeNode.Index % 2 == 0)
{
treeNode.ForeColor = Color.DodgerBlue;
}
else
{
treeNode.ForeColor = Color.Goldenrod;
}
Now what I need to figure out, with someone's help, is how to Loop through ALL layers of nodes and apply my alternating coloring. If I do something along the below lines I can achieve this.
foreach (TreeNode treeNode in treeView1.Nodes[1].Nodes[0].Nodes)
{
if (treeNode.Index % 2 == 0)
{
treeNode.ForeColor = Color.DodgerBlue;
}
else
{
treeNode.ForeColor = Color.Goldenrod;
}
How do I iterate through ALL layers programatically?
Recursion?
Edit: added code for eliminating color repetition
protected void ColorNodes(TreeNode root, Color firstColor, Color secondColor)
{
Color nextColor;
foreach (TreeNode childNode in root.Nodes)
{
nextColor = childNode.ForeColor = childNode.Index % 2 == 0 ? firstColor : secondColor;
if (childNode.Nodes.Count > 0)
{
// alternate colors for the next node
if (nextColor == firstColor)
ColorNodes(childNode, secondColor, firstColor);
else
ColorNodes(childNode, firstColor, secondColor);
}
}
}
private void frmCaseNotes_Load(object sender, System.EventArgs e)
{
foreach (TreeNode rootNode in treeView1.Nodes)
{
ColorNodes(rootNode, Color.Goldenrod, Color.DodgerBlue);
}
}
Dude, this one was serious trouble. The Broadth Search was easy, but you were right. Depth Search was a pain. I hope it helps you. Shame that such nice trick will probably fall into oblivion due to the sheer ammount of questions on this site. The depth algorithm is kind of crude and assume a head node without siblings.
//depth search on TreeView
TreeNode node = trv.Nodes[0];
Stack<TreeNode> list = new Stack<TreeNode>();
list.Push(node);
while (list.Count > 0)
{
while (node.Nodes.Count > 0)
{
list.Push(node.Nodes[0]);
node = node.Nodes[0];
}
//Will always have a leaf here as the current node. The leaf is not pushed.
//If it has a sibling, I will try to go deeper on it.
if (node.NextNode != null)
{
node = node.NextNode;
continue;
}
//If it does NOT have a sibling, I will pop as many parents I need until someone
//has a sibling, and go on from there.
while (list.Count > 0 && node.NextNode == null)
{
node = list.Pop();
}
if (node.NextNode != null) node = node.NextNode;
}
//broadth search on TreeView
Queue<TreeNode> list = new Queue<TreeNode>();
foreach(TreeNode node in trv.Nodes)
{
list.Enqueue(node);
}
foreach(TreeNode node in list)
{
foreach(TreeNode childNode in node.Nodes)
{
list.Enqueue(childNode);
}
}
The best way to do this would be to override the OnPaint event, and provide your own code for drawing in the control.
You can find many examples on overriding the onPaint method online.
EDIT: I actually looked into this some more, and you can set the BackColor of treeview nodes individually already.
Me.TreeView1.Nodes(0).BackColor = Color.AliceBlue
Okay, this is how far I got. Unfortunately it is very ugly and I am still manually coding how DEEP I go into it. Also it doesn't prevent like colors being next to each other. Suggestions?
foreach (TreeNode treeNode in treeView1.Nodes)
{
treeNode.ForeColor = treeNode.Index % 2 == 0 ? Color.DodgerBlue : Color.Goldenrod;
foreach (TreeNode childNode in treeNode.Nodes)
{
childNode.ForeColor = childNode.Index % 2 == 0 ? Color.Goldenrod : Color.DodgerBlue;
foreach (TreeNode childChildNode in childNode.Nodes)
{
childChildNode.ForeColor = childChildNode.Index % 2 == 0 ? Color.DodgerBlue : Color.Goldenrod;
foreach (TreeNode childChildChildNode in childChildNode.Nodes)
{
childChildChildNode.ForeColor = childChildChildNode.Index % 2 == 0 ? Color.Goldenrod : Color.DodgerBlue;
}
}
}
}
Do it recursively on a Control type using the children control from the TreeView root and check to see if the Control type is the type of the node you are looking for, cast, change backcolor and you are done.

Categories