Mapping TreeView to/from xmldoc

Hi,
Developing a trad win app using VS 2010 C#.

Starting from loading a xml file into a XMLDocument object.

 
openedFile = someFile.xml;
xmlReader = new XmlTextReader(openedFile);
Global.mainXMLDoc.Load(xmlReader);
xmlReader.Close();

Open in new window


Next thing I do is load the xml nodes into a TreeView component (System.Windows.Forms)

 
private void AddNodeToTreeView(ref XmlNode inXmlNode, ref TreeNode inTreeNode)
	{
		XmlNode xNode;
		TreeNode tNode;
		XmlNodeList nodeList;
		
		if (inXmlNode.HasChildNodes)
		{
			nodeList = inXmlNode.ChildNodes;
			for (int i = 0; i <= nodeList.Count - 1; i++)
			{
				xNode = inXmlNode.ChildNodes[i];
				inTreeNode.Nodes.Add(new TreeNode(xNode.Name));
				tNode = inTreeNode.Nodes[i];
				AddNodeToTreeView(ref xNode, ref tNode);
			}
		}
	}

Open in new window


Now I have a multi column ListView to show the attributes whenever user selects a node from the TreeView component. Here's where it all gets totally wrong. My first idea was to use the tv.SelectedNode.Index (in the TreeView event listener _AfterSelect). But since this index is calculated relatively its parent the mapping to the xmlNodes is lost.

private void treeView_AfterSelect(object sender, TreeViewEventArgs e, TreeView tv, ListView lv)
{
	lv.Items.Clear();
	ListViewItem lvItem;
	currentNodeName = tv.SelectedNode.Text;
	int currentNodeIx = tv.SelectedNode.Index;
	xmlNodes = Global.mainXMLDoc.GetElementsByTagName(currentNodeName);
	XmlNode xNode = xmlNodes.Item(currentNodeIx);
	string attr;
	string val;

	for (int i = 0; i < xNode.Attributes.Count; i++)
	{
		attr = xNode.Attributes[i].Name;
		val = xNode.Attributes[i].Value;
		lvItem = new ListViewItem(attr);
		string foo = FindXPath(xNode.Attributes[i]);
		lvItem.SubItems.Add(val);
		lvItem.SubItems.Add(foo);
		lv.Items.Add(lvItem);
	}
}

Open in new window


So, is there a way you can do this using these standard components or do I need to design my own?

Cheers!
peer754Asked:
Who is Participating?
 
peer754Connect With a Mentor Author Commented:
Ok, as far as I've been able to test this the HashCode seems to work fine :D
This is how I did it:

I first copy the HashCode from the xmlNode (xNode) into the TreeNode (tNode) using the .Name property of the tNode:

 
private void AddNodeToTreeView(ref XmlNode inXmlNode, ref TreeNode inTreeNode)
{
	XmlNode xNode;
	TreeNode tNode;
	XmlNodeList nodeList;
	
	if (inXmlNode.HasChildNodes)
	{
		nodeList = inXmlNode.ChildNodes;
		for (int i = 0; i <= nodeList.Count - 1; i++)
		{
			xNode = inXmlNode.ChildNodes[i];
			inTreeNode.Nodes.Add(new TreeNode(xNode.Name));
			tNode = inTreeNode.Nodes[i];
			tNode.Name = xNode.GetHashCode().ToString();                   
			AddNodeToTreeView(ref xNode, ref tNode);
		}
	}
}

Open in new window


Now I can look up the corresponding xNode i.e. re-map the tNode by looking-up the HashCode:

 
private void treeView_AfterSelect(object sender, TreeViewEventArgs e, TreeView tv, ListView lv)
{
	lv.Items.Clear();
	ListViewItem lvItem;		// Used for creating listview items.

	currentNodeName = e.Node.Text;
	xmlNodes = Global.mainXMLDoc.GetElementsByTagName(currentNodeName);
	XmlNode xNode = null;
	foreach (XmlNode xn in xmlNodes)
	{
		if (string.Compare(xn.GetHashCode().ToString(), e.Node.Name) == 0)
		xNode = xn;
	}

	string attr;
	string val;

	if (xNode != null)
	{
		for (int i = 0; i < xNode.Attributes.Count; i++)
		{
			attr = xNode.Attributes[i].Name;
			val = xNode.Attributes[i].Value;
			lvItem = new ListViewItem(attr);
			string foo = FindXPath(xNode.Attributes[i]);
			lvItem.SubItems.Add(val);
			lvItem.SubItems.Add(foo);
			lv.Items.Add(lvItem);
		}
	}
}

Open in new window

0
 
MlandaTCommented:
in your XML file... are there any unique properties on each node? say an ID of sorts? or can you post a sample of of the xml file.
0
 
peer754Author Commented:
Noop, but I'm gonna try to use the HashCode function from the xmlNode object but how do I know that this would be unique for every xml node?

Here's a small sample from my xml:

 
<Organisation>
    <MainGroup dataName="SA">
      <HeadGroup dataName="SAA">
        <PlannerGroup dataName="C02"></PlannerGroup>
        <PlannerGroup dataName="C03"></PlannerGroup>
        <PlannerGroup dataName="C04"></PlannerGroup>
        <PlannerGroup dataName="C05"></PlannerGroup>
      </HeadGroup>
      <HeadGroup dataName="SAB">
        <PlannerGroup dataName="C36"></PlannerGroup>
        <PlannerGroup dataName="C37"></PlannerGroup>
      </HeadGroup>
    </MainGroup>
    <MainGroup dataName="SB">
      <HeadGroup dataName="SBB">
        <PlannerGroup dataName="C12"></PlannerGroup>
        <PlannerGroup dataName="C13"></PlannerGroup>
        <PlannerGroup dataName="C14"></PlannerGroup>
        <PlannerGroup dataName="C15"></PlannerGroup>
      <PlannerGroup dataName="C23"></PlannerGroup></HeadGroup>
      <HeadGroup dataName="SBC">
        <PlannerGroup dataName="C30"></PlannerGroup>
        <PlannerGroup dataName="C31"></PlannerGroup>
        <PlannerGroup dataName="C32"></PlannerGroup>
      </HeadGroup>
      <HeadGroup dataName="SBD">
      	<PlannerGroup dataName="C41"></PlannerGroup>
        <PlannerGroup dataName="C44"></PlannerGroup>
      </HeadGroup>
      <HeadGroup dataName="SBE">
      	<PlannerGroup dataName="C19"></PlannerGroup>
      </HeadGroup>
    </MainGroup>
  </Organisation>
  <World>
    <Region dataName="Region North America" ShortName="RNA">
      <SubRegion dataName="11">
        <Country dataName="US" LongName="United States"/>
        <Country dataName="CA" LongName="Canada"/>
      </SubRegion>
    </Region>
    <Region dataName="Region Latin America" ShortName="RLA">
      <SubRegion dataName="21">
        <Country dataName="BM" LongName="Bermuda"/>
      </SubRegion>
      <SubRegion dataName="22">
        <Country dataName="BB" LongName="Barbados"/>
        <Country dataName="CO" LongName="Colombia"/>
        <Country dataName="PE" LongName="Peru"/>
        <Country dataName="VE" LongName="Venezuela"/>
      </SubRegion>
      <SubRegion dataName="24">
        <Country dataName="BO" LongName="Bolivia"/>
        <Country dataName="CL" LongName="Chile"/>
      </SubRegion>
    </Region>
  </World>

Open in new window

0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

 
MlandaTCommented:
you can use XPath to find the right node... not clean, but might work. to do this... perhaps start with this change - this keeps track of more details there:

inTreeNode.Nodes.Add(new TreeNode(xNode.Name));

Open in new window


should be:

TreeNode newNode = new TreeNode();

newNode.Text = xNode.Name;
newNode.Text = xNode.Attributes["dataName"].Value;

inTreeNode.Nodes.Add(xn);

Open in new window


do you have a screenshot of what the multi column ListView should look like?
0
 
MlandaTCommented:
i the HashCode can give us a unique value then by all means! use that! it "might" make life "easier". we will still have the problem of linking the hashcode back to the XML file
0
 
peer754Author Commented:
Using the HashCode to map a TreeNode to/from a XMLNode seems to do the trick!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.