I am having difficulty recreating a tree view from an XML file in a WPF application
I require the tree structure to be displayed with check boxes
Here is a typical XML file I will be reading
Here is the MainWindow Class that uses a Node class for the check boxes
namespace WpfApplication
{
public partial class MainWindow : Window
{
public ObservableCollection<Node> Nodes { get; private set; }
public MainWindow()
{
Nodes = new ObservableCollection<Node>();
Nodes.Clear();
InitializeComponent();
XmlDocument doc = new XmlDocument();
doc.Load(@"C:\Temp\simple.xml");
XmlNode root = doc.DocumentElement;
TreeViewItem testItems = new TreeViewItem();
//Read in the XML and create parent child nodes
xmlToParentChildNodes(root);
treeView.ItemsSource = Nodes;
}
private void xmlToParentChildNodes(XmlNode node)
{
var parent = new Node() { Text = node.Name.ToString() };
var children = node.ChildNodes.Count;
int currentNodeCount = Nodes.Count;
if (node.ChildNodes.Count > 0)
// Dont add children to the view if they dont have a parent
{
Nodes.Add(parent);
}
foreach (XmlNode child in node.ChildNodes)
{
var childNode = new Node() { Text = child.Name.ToString() };
//*********************** Debug *********************
System.Diagnostics.Debug.WriteLine("Node Reference=" + currentNodeCount +" Parent=" + node.Name.ToString() + " No of Children=" + children + " childNode=" + child.Name.ToString());
//*********************** Debug ********************
parent.Children.Add(childNode);
xmlToParentChildNodes(child);
}
}
The following structure is produced
| Node | Parent | Children |
| 0 | A | B,E |
| 1 | B | BTest1,BTest2,C |
| 2 | C | D |
| 3 | D | DTest1,DTest2 |
| 4 | E | F |
| 5 | F | FTest1, FTest2 |
A recursive method is probably required to recreate the hierarchy - I
am a novice programmer and have been strugglling with this for a long time.
Could somebody please help?
Jaganathan BantheswaranPosted Dec 20, 2013, 1:31 AM
namespace WpfApplication1
{
///
/// Interaction logic for MainWindow.xaml
///
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
const string xml = @"
";
var doc = new XmlDocument();
doc.LoadXml(xml);
if (doc.ChildNodes.Count > 0)
{
var rootNode = new TreeNode(doc.ChildNodes[0].Name);
var nodes = TreeNode.Traverse(rootNode, doc.ChildNodes);
_treeView.ItemsSource = nodes;
}
}
}
public class TreeNode : IEnumerable<TreeNode>
{
private readonly Dictionary<string, TreeNode> _childs = new Dictionary<string, TreeNode>();
public readonly string Id;
public TreeNode Parent { get; private set; }
public TreeNode(string id)
{
Id = id;
Name = id;
}
public string Name
{
get; set;
}
public TreeNode GetChild(string id)
{
return _childs[id];
}
public void Add(TreeNode item)
{
if (item.Parent != null)
{
item.Parent._childs.Remove(item.Id);
}
item.Parent = this;
_childs.Add(item.Id, item);
}
public IEnumerator<TreeNode> GetEnumerator()
{
return _childs.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count
{
get { return _childs.Count; }
}
public static TreeNode Traverse(TreeNode treeNode, XmlNodeList nodes)
{
if (treeNode == null) throw new ArgumentNullException("treeNode", new Exception("RootNode can't be Null"));
foreach (XmlNode node in nodes)
{
var childNode = new TreeNode(node.Name);
treeNode.Add(node.ChildNodes.Count > 0 ? Traverse(childNode, node.ChildNodes) : childNode);
}
return treeNode;
}
}
}
Jaganathan BantheswaranPosted Dec 22, 2013, 12:01 AM
Damian HelaeyPosted Dec 20, 2013, 11:58 AM
Thank you for your help this has enabled me moved on with my coding. I will now work on binding some checkboxes - and probably post another question in a couple of weeks
Damian HelaeyPosted Dec 19, 2013, 6:37 PM
Damian HelaeyPosted Dec 19, 2013, 3:27 PM
Hi Jaganathan,
Thank you for your help!
Your TraverseNodes method is quite elegant and recreates the hierarchy
as required. I am working on getting this integrated with my code as I need to
use my Node class instead of the TreeNode class
I have upload my Node class - the copy and paste tool is not usable
Jaganathan BantheswaranPosted Dec 19, 2013, 1:29 AM
Here is the custom TreeNode implementation.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
namespace TestConsoleApp
{
class Program
{
private static void Main(string[] args)
{
const string xml = @"
";
var doc = new XmlDocument();
doc.LoadXml(xml);
if (doc.ChildNodes.Count > 0)
{
var rootNode = new TreeNode(doc.ChildNodes[0].Name);
var nodes = TraverseNodes(rootNode, doc.ChildNodes[0].ChildNodes);
Console.ReadKey();
}
}
private static TreeNode TraverseNodes(TreeNode treeNode, XmlNodeList nodes)
{
if (treeNode == null) throw new ArgumentNullException("treeNode", new Exception("RootNode can't be Null"));
foreach (XmlNode node in nodes)
{
var childNode = new TreeNode(node.Name);
treeNode.Add(node.ChildNodes.Count > 0 ? TraverseNodes(childNode, node.ChildNodes) : childNode);
}
return treeNode;
}
}
//Source: http://stackoverflow.com/a/9860455
class TreeNode : IEnumerable
{
private readonly Dictionary
public readonly string Id;
public TreeNode Parent { get; private set; }
public TreeNode(string id)
{
Id = id;
}
public TreeNode GetChild(string id)
{
return _childs[id];
}
public void Add(TreeNode item)
{
if (item.Parent != null)
{
item.Parent._childs.Remove(item.Id);
}
item.Parent = this;
_childs.Add(item.Id, item);
}
public IEnumerator
{
return _childs.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count
{
get { return _childs.Count; }
}
}
}