I have to load an Xml document and display in a tree view in a winform. here is a piece of code. Please tell whats the error.
private void AddingNodesToTree(ref XmlNode xnode, ref TreeNode tnode)
{
TreeNode subNode = treeNodes.Add(xnode.Name);
subNode.Tag = xnode;
foreach (XmlNode subElement in xnode.ChildNodes)
{
AddingNodesToTree(subNode.Nodes, subElement);
}
}
after this i select node in that tree to display the attributes of selected node:
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
XmlNode xNode = e.Node.Tag as XmlNode;
if (xNode != null)
{
foreach (XmlNode subNode in xNode.ChildNodes)
{
listBox1.Items.Add(subNode.Name);
}
}
}
WHats possible error in this code? Please rectify.
Well for one thing, in your recursive call to AddingNodesToTree you're not specifying ref on the arguments. It's not at all clear why they're on the parameters in the first place though. Your arguments to the recursive call also appear to be the wrong type. Is it actually a recursive call, or are you calling an overload which you haven't shown?
The second obvious problem is that you're not using the tnode parameter within AddingNodesToTree. Should this line:
TreeNode subNode = treeNodes.Add(xnode.Name);
actually be this:
TreeNode subNode = tnode.Add(xnode.Name);
Finally, you haven't told us what's actually wrong. Does your code not compile, or not work as you expected? If it's the former, what's the compiler error? If it's the latter, please give details of the actual behaviour vs the expected behaviour.
I guess you have a compiler error
private void AddingNodesToTree(ref XmlNode xnode, ref TreeNode tnode)
{
TreeNode subNode = treeNodes.Add(xnode.Name);
subNode.Tag = xnode;
foreach (XmlNode subElement in xnode.ChildNodes)
{
// you call it with the wrong params?
AddingNodesToTree(subNode.Nodes, subElement);
//should be
AddingNodesToTree(ref subElement, ref subNode);
}
}
My guess: You want to show the attributes of the node, so iterate over xNode.Attributes instead of xNode.ChildNodes. Optionally, clear the listview before adding the attributes.
Related
How to find the index of every root folder in a treeview?
Let's say there's a treeview with 4 root nodes. They're all on the same level and all of them have child nodes (not displayed):
|-a
|-b
|-c
|-d
Now let's suppose there's a selected node on the branch of the "c" root node. How could I get the index of the "c" node? (In this case, it's the third one between root nodes).
So, given a selected node, how could I get the index of its root node?
To achieve your task, you should find clicked node's parent and then parent's parent etc... So, we need a recursion here.
Take a look at sample code (with comments):
private void Form1_Load(object sender, EventArgs e)
{
//add test data on form load (you can do it on form design, too.
//there are 4 root nodes and each of them has one subnode.
//Additionally, c's first node, called 'c-1', has it's own child.
treeView1.Nodes.Add(new TreeNode("a"));
treeView1.Nodes.Add(new TreeNode("b"));
treeView1.Nodes.Add(new TreeNode("c"));
treeView1.Nodes.Add(new TreeNode("d"));
treeView1.Nodes[0].Nodes.Add(new TreeNode("a-1"));
treeView1.Nodes[1].Nodes.Add(new TreeNode("b-1"));
treeView1.Nodes[2].Nodes.Add(new TreeNode("c-1"));
treeView1.Nodes[3].Nodes.Add(new TreeNode("d-1"));
treeView1.Nodes[2].Nodes[0].Nodes.Add(new TreeNode("c-1-1"));
//expand those nodes to see things clearly
treeView1.ExpandAll();
//subscribe to after select event. When user selects one node, treeView1_AfterSelect method will be called.
//this can be done on form designer too, on properties panel
treeView1.AfterSelect += treeView1_AfterSelect;
}
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
//this method will be called when you select node
//find topmost parent by calling method FindTopMostParent and passing it selected node
var topmostParent = FindTopMostParent(e.Node);
//here's your index of topmost node (parent or grandparent or grand-grand of selcted node(
var index = treeView1.Nodes.IndexOf(topmostParent);
}
private TreeNode FindTopMostParent(TreeNode node)
{
//first, we check if passed node has parent. If not, return that node, because it's the topmost one
//then, repeat that search for parent again and again until you find that node which does not have parent
while (node.Parent != null)
return FindTopMostParent(node.Parent);
//return parentless node :)
return node;
}
I have some nodes added to my TreeView (trvP). The root element has Tag property set to Root.
I'm trying to make it so if I check the root element, all other nodes will have the same status. However, executing the code below results in StackOverflowException.
private void trvP_AfterCheck(object sender, TreeViewEventArgs e)
{
if(e.Node.Tag.Equals("Root"))
{
var nodes = TreeViewExtensions.GetAllNodes(e.Node.TreeView);
foreach (TreeNode node in nodes)
node.Checked = e.Node.Checked;
}
}
The code for GetAllNodes function:
public static List<TreeNode> GetAllNodes(this TreeView _trv)
{
List<TreeNode> result = new List<TreeNode>();
foreach (TreeNode child in _trv.Nodes)
{
result.AddRange(child.GetAllNodes());
}
return result;
}
public static List<TreeNode> GetAllNodes(this TreeNode _trn)
{
List<TreeNode> result = new List<TreeNode>();
result.Add(_trn);
foreach (TreeNode child in _trn.Nodes)
{
result.AddRange(child.GetAllNodes());
}
return result;
}
It seems from debugging that it runs the var nodes = ... piece of code over and over, while only setting single node inside the foreach loop (the root node). However, nodes is a proper list of nodes with right values.
I can't see why this is executing over and over resulting in an exception.
Your GetAllNodes() extension for a TreeView starts with the first child node and calls the GetAllNodes() extension for this TreeNode.
This GetAllNodes() extension adds this very TreeNode to the result list.
So the first TreeNode in your list is your root node again.
This means in the line
node.Checked = e.Node.Checked;
you set the Checked property of your root node, which in turn calls the handler trvP_AfterCheck again for this root node. This now repeats infinitly, flooding your stack and raising the StackOverflowException.
To solve this, filter out the root node:
private void trvP_AfterCheck(object sender, TreeViewEventArgs e)
{
if(e.Node.Tag.Equals("Root"))
{
var nodes = e.Node.TreeView.GetAllNodes();
foreach (TreeNode node in nodes)
{
if (node == e.Node) continue; // don't do it for root again
node.Checked = e.Node.Checked;
}
}
}
Btw: the nice thing about extension methods is that you can call them syntactically as if they were instanc methods. So this
var nodes = TreeViewExtensions.GetAllNodes(e.Node.TreeView)
can simply be written as
var nodes = e.Node.TreeView.GetAllNodes();
you are calling GetAllNodes recursively which makes loop into infinite state..
try
public static List<TreeNode> GetAllNodes(this TreeView _trv)
{
List<TreeNode> result = new List<TreeNode>();
foreach (TreeNode child in _trv.Nodes)
{
result.Add(child);
}
return result;
}
when you are already looping to treenode into _trv.Nodes, you jst need to add current node into foreach statement..
I have a TreeView and an associated ImageList. What are the steps to add images to the Parent and child nodes ?
All the nodes are being added from the code. Nothing is done from the Design.
public void fill_tree()
{
host_listbox_new.Items.Clear();
foreach (KeyValuePair<string, host_config> hlitem in host_list)
{
string sitem = hlitem.Key;
if (host_list[sitem].sessionOptions == null)
host_list[sitem].sessionOptions = new SessionOptions();
host_list[sitem].sessionOptions.Protocol = Protocol.Sftp;
host_list[sitem].sessionOptions.HostName = host_list[sitem].ip;
host_list[sitem].sessionOptions.UserName = host_list[sitem].username;
host_list[sitem].sessionOptions.Password = host_list[sitem].password;
host_list[sitem].sessionOptions.PortNumber = Convert.ToInt32(host_list[sitem].port);
//host_list[sitem].sessionOptions.SshHostKeyFingerprint = host_list[sitem].rsa;
if (treeView1.SelectedNode != null)
{
treeView1.SelectedNode.Nodes.Add(hlitem.Key.ToString());
}
else
{
treeView1.Nodes[0].Nodes.Add(hlitem.Key.ToString());
}
}
}
private void Parent_Load(object sender, EventArgs e)
{
read_process_config();
read_host_config();
host_listbox.Items.Clear();
treeView1.BeginUpdate();
treeView1.Nodes.Add("Servers");
fill_tree();
treeView1.EndUpdate();
treeView1.ExpandAll();
connect_server_bttn.Enabled = false;
}
i want to add items i.e child nodes to Server Parent node each of them having one image before them ( green image if hlitem.Value.connected is true. red image if hlitem.Value.connected is false)
But i have no idea about treeview or imagelist.
Can anyone help me about the whole thing?
The Add command returns a reference to the new Node. You can use it to style the Node.
Change your code to this:
if (treeView1.SelectedNode != null)
{
TreeNode tn =treeView1.SelectedNode.Nodes.Add(hlitem.Key.ToString());
tn.ImageIndex = yourIndex;
}
else
{
TreeNode tn =treeView1.Nodes[0].Nodes.Add(hlitem.Key.ToString());
tn.ImageIndex = yourIndex;
}
Or whatever logic you need to set the index.
If you need the parent node's index you could write:
tn.ImageIndex = tn.Parent.ImageIndex;
You may also want ot check out the other formats of the Add method. Some let you include the ImageIndex directly. You can also include the SelectedIndex; especially if you don't want that you should include it to prevent the Tree using its default SelectedIndex!
This will set the node to show the 2nd image, whether selected or not:
TreeNode tn =treeView1.Nodes[0].Nodes.Add(sitem, sitem, 1,1 );
Since you can't set a property of an object before you have created it, you can't set the Child nodes when you create the parent node. Instead you can use a simple function to do the changes:
void copyImgIndexToChildren(TreeNode tn)
{
if (tn.Nodes.Count > 0)
foreach (TreeNode cn in tn.Nodes) cn.ImageIndex = tn.ImageIndex;
}
void copyImgIndexToAllChildren(TreeNode tn)
{
if (tn.Nodes.Count > 0)
foreach (TreeNode cn in tn.Nodes)
{
cn.ImageIndex = tn.ImageIndex;
copyImgIndexToAllChildren(cn);
}
}
The first method changes the direct ChildNodes only , the 2nd recursively changes all levels below the starting node.
BTW: Is there a reason to use hlitem.Key.ToString() in your code instead of sitem?
I have created a treeview with parent and childnodes created dynamically.Also have enabled checkbox property true.hence got check boxes for each node.
The problem is how to name these check boxes so that for a particular user if the value is true, the checkbox should be checked, else if the value is false the checkbox needs to be unchecked. true or false value is stored in a particular column in a db.
Please follow the code I've provided it might give you some Idea from what I understand from your question. I've provided the link as well.
http://msdn.microsoft.com/en-us/library/wwc698z7(v=vs.90).aspx
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);
}
}
you can check which node is checked by the following code
foreach (TreeNode node in yourtreeview.Nodes)
{
if (node.Checked)
{ //here You can check here your parent nodes is checked or not
//your calculations
}
foreach (TreeNode ChildNode in node.Nodes)
{
if (ChildNode.Checked)
{ // here you can check your 2nd level nodes
}
foreach (TreeNode childofChild in ChildNode.Nodes)
{
if (childofChild.Checked)
{ here you can check your 3rd level node }
foreach (TreeNode GrandChildofChild in childofChild.Nodes)
{
if (GrandChildofChild.Checked)
{
//here you can check your fourth level node
}
}
}
}
}
I have a treelist in my form with checkboxes enabled. I need to add anything checked to a list so I can write that list out. If I check any parent nodes (or highest level nodes) it includes them. If I select any parent nodes it also selects its children nodes (this is intentional), and displays those. But If I check any child nodes only, it won't add them to my list.
//check to see if there are any nodes checked
bool nodeHasCheck = false;
foreach (TreeNode n in nodes)
{
if (n.Checked)
{
nodeHasCheck = true;
break;
}
GetExtendedFeatures(n.Nodes);
}
//only return stuff if something's checked
if (nodeHasCheck == true)
{
foreach (TreeNode n in nodes)
{
if (n.Checked)
{
//n.BackColor = Color.Black;
nodeList.Add(n.Text);
}
GetExtendedFeatures(n.Nodes);
}
It also appears that if I select 2 parent nodes, the recursion that occurs (Think that's the right term) is causing it to find the first checked node, then starts over, and adds that same checked node a second time before it hits the second set of nodes.
I provided my node test, hopefully it's enough to identify why it's not detecting child nodes selected without the parent node selected.
UPDATED - 3/18/13
My button click code:
private void btnGenerate_Click(object sender, EventArgs e)
{
ScanNodes(treeView1.Nodes[0]);
}
private void ScanNodes(TreeNode parent)
{
foreach (TreeNode node in parent.Nodes)
{
if (node.Checked)
{
nodeList.Add(node.Text.ToString());
}
if (node.Nodes.Count > 0)
{
ScanNodes(node);
}
}
var message = string.Join(Environment.NewLine, nodeList);
message = message.Replace(Environment.NewLine, ", ");
MessageBox.Show(message);
nodeList.Clear();
}
To get a List of all the selected nodes in a TreeView you can use the following:
Supose the list is named nodeList:
//We First declare a recursive method to loop through all nodes,
//we need to pass a root node to start
private void ScanNodes(TreeNode parent)
{
foreach (TreeNode node in parent.Nodes)
{
if (node.Checked)
{
nodeList.Add(node.Text);
}
if (node.Nodes.Count > 0)
{
ScanNodes(node);
}
}
}
With that set up You just need to call the ScanNodes method and pass the root node of your TreeView:
ScanNodes(treeView1.Nodes[0]);
Regards,