I'm trying to import an XML file of nodes into the same node structure in a TreeView using C#. I have found a lot of example that use a single node structure, but have had a lot of issues traversing the XML file and populating the TreeView with it. This is a sample of the XML file:
<?xml version="1.0"?>
<xmlRoot>
<ProductGroup>
<Group>
<GroupName>Soda</GroupName>
<Classifications>
<Classification>
<ClassificationName>Regular</ClassificationName>
<Containers>
<Container>
<ContainerType>Can</ContainerType>
<ContainerName>SmallCan</ContainerName>
</Container>
<Container>
<ContainerType>bottle</ContainerType>
<ContainerName>SmallBottle</ContainerName>
</Container>
</Containers>
</Classification>
<Classification>
<ClassificationName>Diet</ClassificationName>
<Containers>
<Container>
<ContainerType>Can</ContainerType>
<ContainerName>SmallCan</ContainerName>
</Container>
</Containers>
</Classification>
</Classifications>
</Group>
<Group>
<GroupName>Water</GroupName>
<Classifications>
<Classification>
<ClassificationName>Regular</ClassificationName>
<Containers>
<Container>
<ContainerType>Bottle</ContainerType>
<ContainerName>EcoBottle</ContainerName>
</Container>
</Containers>
</Classification>
</Classifications>
</Group>
</ProductGroup>
</xmlRoot>
I've tried using something like this:
treProducts.Nodes.Clear();
XDocument xdoc = XDocument.Load("ProductDocument.xml");
foreach (XElement groupElement in xdoc.Descendants("Group"))
{
treProducts.Nodes.Add(groupElement.Element("GroupName").Value);
treProducts.SelectedNode = treProducts.Nodes[groupElement.Element("GroupName").Value];
foreach (XElement ClassificationElement in groupElement.Descendants("Classification"))
{
treProducts.SelectedNode.Nodes.Add(groupElement.Element("ClassificationName").Value);
treProducts.SelectedNode = treProducts.Nodes[groupElement.Element("ClassificationName").Value];
foreach (XElement ContainerElement in groupElement.Descendants("Container"))
{
treProducts.SelectedNode.Nodes.Add(ContainerElement.Element("ContainerName").Value);
}
}
}
I'm trying to get the tree to show:
Soda
Regular
SmallCan
SmallBottle
Diet
SmallCan
Water
Regular
EcoBottle
...but the tree is only showing Soda and it seems to skip the rest, except if I comment out the nested foreach statements, it will show Soda and Water. There's something wrong with the syntax I'm using and I'm wondering if someone who understands Linq better can help see where the code is wrong.
I suggest recursion
Note: dbc's answer is probably better if your XML structure is likely to change, but if you are given it as it currently stands, and it won't change - then this will slurp it right into the tree quickly, without a lot of overhead.
The reason this is complicated is that your tree node hierarchy does not correspond 1-1 to your XML hierarchy. In situations like this, I suggest introducing intermediate classes to provide a view into the base XML model data. In WPF these classes would be the View Model, but the windows forms
TreeView
doesn't support data binding. Despite this, the abstraction of a view model is useful here.First, some basic view model interfaces and classes to tie together
TreeNode
andXElement
hierarchies:Next, a couple extension classes:
Next, view models for the three levels of your tree:
Now, building your tree becomes quite simple:
And the result:
Later, if you wish to add editing functionality to your tree, you can add the appropriate methods to
ITreeNodeViewModel
-- for instance, a setter method forText
. Since theITreeNodeViewModel
has saved itself in theTreeNode.Tag
the appropriate methods will be available.You are using the wrong variable in your loop over the
Classification
Elements. ReplacegroupElement
withClassificationElement
inside the loop.Change:
to