Im using c#.net windows form application. I have a xml file .I need to populate this xml file into a tree view. I can do that using "xml document" but i need to do it using xElement.
Please refer to the article Populating a TreeView Control from XML, which says
This post describes how to populate a WinForms TreeView control from an XML file assuming you are targeting the .NET Framework Version 3.5.
XElement doc = XElement.Load("testXML.xml");
TreeNode stateNode;
TreeNode regionNode;
foreach (XElement state in doc.Descendants("State"))
{
stateNode = treeView1.Nodes.Add(state.Attribute("name").Value);
foreach (XElement region in state.Descendants("Region"))
{
regionNode =
stateNode.Nodes.Add(region.Attribute("name").Value);
foreach (XElement area in region.Descendants("Area"))
{
regionNode.Nodes.Add(area.Attribute("name").Value);
}
}
}
The following Class loads your .xml into an XElement collection then iterates over it, adding nodes according to their position in the original document and using XML node attributes for tree node naming:
using System.Windows.Forms;
using System.Xml.Linq;
namespace _Solution.Class
{
class Load
{
public void tree_pop(TreeView treeview)
{
treeview.Nodes.Clear();
XElement doc = XElement.Load("xml_file.xml");
TreeNode root = new TreeNode("root");
treeview.Nodes.Add(root);
add_nodes(root, doc);
treeview.ExpandAll();
}
private void add_nodes(TreeNode t_node, XElement x_node)
{
foreach (XElement node in x_node.Elements())
{
TreeNode n_node = t_node.Nodes.Add(node.Attribute("name").Value);
add_nodes(n_node, node);
if (n_node.Nodes.Count == 0) n_node.EnsureVisible();
}
}
}
}
Instantiate and call as follows:
Load load = new Load();
private void Form1_Load(object sender, EventArgs e)
{
load.tree_pop(treeview);
}
What's happening in tree_pop is that you're clearing your treeview of any nodes that may already exist, loading your .xml document into an XElement collection, establishing your treeview's root node, calling add_nodes to iterate over the XElement collection then expanding the treeview nodes.
What's happening in add_nodes is that you're iterating over the XElement collection as passed from tree_pop, creating and adding a new node to the treeview then searching each XElement for children and, if found, adding those to the node you just added to the tree.
For copy / paste, remember to adjust your Class namespace to match that of your solution.
Try the following:
var data = XElement.Load(source.xml);
foreach (XElement single in data.Elements())
{
treeNode.Nodes.Add(single.Element("name of element").Value);
}
Related
I have a Windows Forms TreeView that needs to be saved as a xml file.
The structure of the TreeView is like this:
- Parent
- Child 1 (Any value)
- Child 2
- Child 1 (Any value for a child)
Every TreeNode that has children needs to be saved as a element, and every TreeNode that does not have children needs to be saved as a attribute to it's parent TreeNode
This means the above would result in the following xml:
<?xml version="1.0" encoding="utf-8"?>
<Parent Child1="Any value">
<Child2 Child1="Any value for a child" />
</Parent>
I tried using the following code, but it did not work when the TreeNodes with no children where below the TreeNodes with children and I couldn't really figure out a good way of doing it.
public void SerializeTreeView(TreeView treeView, string fileName)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter textWriter = XmlWriter.Create(fileName, settings);
// Writing the xml declaration tag
textWriter.WriteStartDocument();
// Save the nodes, recursive method
SaveNodes(treeView.Nodes, textWriter);
// End the xml document
textWriter.WriteEndDocument();
textWriter.Close();
}
private void SaveNodes(TreeNodeCollection nodesCollection, XmlWriter textWriter)
{
for (int i = 0; i < nodesCollection.Count; i++)
{
TreeNode node = nodesCollection[i];
if (node.Nodes.Count > 0)
{
textWriter.WriteStartElement(node.Name);
}
else
{
textWriter.WriteAttributeString(node.Name, "Attribute value");
}
if (node.Nodes.Count > 0)
SaveNodes(node.Nodes, textWriter);
if (node.Nodes.Count > 0)
textWriter.WriteEndElement();
}
}
EDIT:
The problem with the current code is that if I add a TreeNode that has any children and is ABOVE a TreeNode with no children, it gives me the following error:
Token StartAttribute in state Element Content would result in an invalid XML document.
This happens at:
textWriter.WriteAttributeString(node.Name, "Attribute value");
I solved it by sorting the TreeView by child node count (Meaning that the TreeNode with NO children will ALWAYS be below a TreeNode without children)
The solution works, but I would like to figure out why the error occurred and how to fix it.
How are you filling the TreeView? Are you actually giving the object keys or just titles? Try replacing the two occurences of "node.Name" with "node.Text" (and, for reasons of code sanity, refactoring the multiple checks for Count > 0):
EDIT: ok, try this:
private void SaveNodes(TreeNodeCollection nodesCollection, XmlWriter textWriter)
{
foreach (var node in nodesCollection.OfType<TreeNode>().Where(x => x.Nodes.Count == 0))
textWriter.WriteAttributeString(node.Name, "Attribute value");
foreach (var node in nodesCollection.OfType<TreeNode>().Where(x => x.Nodes.Count > 0))
{
textWriter.WriteStartElement(node.Name);
SaveNodes(node.Nodes, textWriter);
textWriter.WriteEndElement();
}
}
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);
}
}
I use Win forms treeview class. I need to have possibililty to navigate to specified node by its fullpath propety. i.e. I have fullpath ("country\region1\city2") and wish to select this node by this path automatically. Can anyone help me?
This is treeview navigation by msdn
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);
}
}
This could help you too
codeproject variant of explorer with treeview navigation
I'm new to Umbraco and I like it so far, I understand how it works but I'd like to know how, and what is the best way, to create usercontrols that display some informations from umbraco's DB? When it's simple, I do it with XSL template but now I need more possibilities.
What I try to do is have a UC that connect to Umbraco's DB, fetch all documents of documentType "NewsItem" and list them in my UC.
I found this post : Umbraco: List Child Nodes in User Control but it's not quite it since I don't want to hardcode the nodeId, I want to find my news depending on DocumentType.
I now that there's an API to acces umbraco's data but did not find any exemple. I also watch lots of videos on umbraco.tv but still do not have a good idea of what's the best way to do it. There's also LINQ to Umbraco (http://our.umbraco.org/wiki/reference/api-cheatsheet/linq-to-umbraco) but not sure if it's a good way of doing this.
Also, is there a way to test the Usercontrol inside an other WebProject? What I mean is to connect to Umbraco's db in an other project, so that you don't have to go in umbraco's website to test it?
Thanks a lot!
There are several areas to your question which I'll try and address one at a time.
Using umbraco.presentation.nodefactory to get Nodes of a specific type. For this example I'm going to assume all your NewsItems are children of a specific node in this case node id 1024.
using umbraco.presentation.nodeFactory;
namespace cogworks.usercontrols
{
public partial class ExampleUserControl : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
var specificNode = new Node(1024);
var childNodes = specificNode.Children;
foreach(var node in childNodes)
{
if(node.NodeTypeAlias == "NewsItem")
{
//Do something with your NewsItem node!
}
}
}
}
}
This is probably not the most efficient way but is OK as an example.
An example of walking the node tree recursively and adding the found nodes to a list:
public static List<Node> SelectChildrenByNameRecursive(Node node, string docType)
{
var nodes = new List<Node>();
foreach (Node child in node.Children)
{
FindChildrenByDocType(child, docType, ref nodes);
}
return nodes;
}
private static void FindChildrenByDocType(Node node, string docType, ref List<Node> nodes)
{
if (node.NodeTypeAlias == docType)
{
nodes.Add(node);
}
foreach (Node childNode in node.Children)
{
FindChildrenByDocType(childNode, docType, ref nodes);
}
}
Again just example code...
Testing Umbraco, you'll always need to be running in a an instance of Umbraco as nodefactory is an API on top of the in memory content cache.
Further reading
http://blog.hendyracher.co.uk/umbraco-helper-class/
http://our.umbraco.org/wiki/how-tos/useful-helper-extension-methods-(linq-null-safe-access)
I have a user control in which I need to return child nodes based on parentID. I am able to get the parentID, but don't know the syntax for returning child nodes.
Getting child nodes is pretty straightforward.
Not sure how far you are with your code so here's a complete example with the various options:
using umbraco.presentation.nodeFactory;
namespace cogworks.usercontrols
{
public partial class ExampleUserControl : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
//If you just want the children of the current node use the following method
var currentNode = Node.GetCurrent();
//If you need a specific node based on ID use this method (where 123 = the desired node id)
var specificNode = new Node(123);
//To get the children as a Nodes collection use this method
var childNodes = specificNode.Children;
//Iterating over nodes collection example
foreach(var node in childNodes)
{
Response.Write(string.Format("{0}<br />", node.Name));
}
//To get the nodes as a datatable so you can use it for DataBinding use this method
var childNodesAsDataTable = node.ChildrenAsTable();
//Databind example
GridViewOnPage.DataSource = childNodesAsDataTable;
GridViewOnPage.DataBind();
}
}
}