TreeView with XML






3.08/5 (6 votes)
Saving anbd loading a TreeView control to and from an XML file.
Introduction
The purpose of this article is to demonstrate the saving and loading of System.Windows.Forms.TreeView
control from an XML file. XmlTextReader
and XmlTextWriter
of the System.Xml
namespace are used for reading and generating XML files, respectively. It also demonstrates a simple XML file viewer using a TreeView
control.
Background
The real functionality is enclosed in a class called TreeViewSerializer
. It has two main responsibilities:
- Saving the
TreeView
to a specified XML file. - Loading the
TreeView
from any specified XML file.
The structure of an XML file used for serializing a TreeView
is quite simple. Following is a sample XML file included with the attached project:
<?xml version="1.0" encoding="us-ascii" ?>
<TreeView>
<node text="Asia" imageindex="0">
<node text="China" imageindex="-1" tag="Largest Population">
<node text="Beijing" imageindex="-1" /></node>
<node text="Pakistan" imageindex="4" />
<node text="India" imageindex="5" />
<node text="Srilanka" imageindex="6" />
</node>
<node text="Europe" imageindex="1">
<node text="Germany" imageindex="6" />
</node>
<node text="America" imageindex="2" />
<node text="Africa" imageindex="3" />
</TreeView>
After the XML declaration, all the nodes are enclosed in a TreeView
tag. The TreeView
tag may contain multiple node
tags. The node
tag can also contain other node
tags. Each node
tag can have three attributes:
Text
ImageIndex
Tag
I have serialized the above three attributes of the System.Windows.Forms.TreeNode
object, it can be easily extended to include other attributes.
XmlNodeTag
, XmlNodeTextAtt
, XmlNodeTagAtt
, and XmlNodeImageIndexAtt
are the constants defined in the TreeViewSerializer
class:
// Xml tag for node, e.g. 'node' in case of <node></node>
private const string XmlNodeTag = "node";
// Xml attributes for node e.g. <node text="Asia" tag=""
// imageindex="1"></node>
private const string XmlNodeTextAtt = "text";
private const string XmlNodeTagAtt = "tag";
private const string XmlNodeImageIndexAtt = "imageindex";
Using the code
The deserialization is performed by the DeserializeTreeView
method which uses XmlTextReader
to parse through the XML document and fill the TreeView
object. Following is the definition of the DeserializeTreeView
method:
public void DeserializeTreeView(TreeView treeView, string fileName)
{
XmlTextReader reader = null;
try
{
// disabling re-drawing of treeview till all nodes are added
treeView.BeginUpdate();
reader = new XmlTextReader(fileName);
TreeNode parentNode = null;
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name == XmlNodeTag)
{
TreeNode newNode = new TreeNode();
bool isEmptyElement = reader.IsEmptyElement;
// loading node attributes
int attributeCount = reader.AttributeCount;
if (attributeCount > 0)
{
for (int i = 0; i < attributeCount; i++)
{
reader.MoveToAttribute(i);
SetAttributeValue(newNode,
reader.Name, reader.Value);
}
}
// add new node to Parent Node or TreeView
if(parentNode != null)
parentNode.Nodes.Add(newNode);
else
treeView.Nodes.Add(newNode);
// making current node 'ParentNode' if its not empty
if (!isEmptyElement)
{
parentNode = newNode;
}
}
}
// moving up to in TreeView if end tag is encountered
else if (reader.NodeType == XmlNodeType.EndElement)
{
if (reader.Name == XmlNodeTag)
{
parentNode = parentNode.Parent;
}
}
else if (reader.NodeType == XmlNodeType.XmlDeclaration)
{
//Ignore Xml Declaration
}
else if (reader.NodeType == XmlNodeType.None)
{
return;
}
else if (reader.NodeType == XmlNodeType.Text)
{
parentNode.Nodes.Add(reader.Value);
}
}
}
finally
{
// enabling redrawing of treeview after all nodes are added
treeView.EndUpdate();
reader.Close();
}
}
As XmlTextReader
parses through the XML document, appropriate actions are taken depending on the NodeType
. If the NodeType
is Element
, a new TreeNode
is created and its properties are set using the XML node attributes. The ParentNode
is set to the new TreeNode
in case of non-empty elements so that its child nodes are deserialized. If an EndElement
is encountered, the ParentNode
is set to the parent of the current parent node indicating that all the child nodes of the current node are deserialized.
For setting the Text
, Tag
, and ImageIndex
properties of a TreeNode
, the SetAttributeValue
method is called. It has the following implementation:
/// <summary>
/// Used by Deserialize method for setting properties of
/// TreeNode from xml node attributes
/// </summary>
private void SetAttributeValue(TreeNode node,
string propertyName, string value)
{
if (propertyName == XmlNodeTextAtt)
{
node.Text = value;
}
else if (propertyName == XmlNodeImageIndexAtt)
{
node.ImageIndex = int.Parse(value);
}
else if (propertyName == XmlNodeTagAtt)
{
node.Tag = value;
}
}