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:
="1.0"="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:
private const string XmlNodeTag = "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
{
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;
int attributeCount = reader.AttributeCount;
if (attributeCount > 0)
{
for (int i = 0; i < attributeCount; i++)
{
reader.MoveToAttribute(i);
SetAttributeValue(newNode,
reader.Name, reader.Value);
}
}
if(parentNode != null)
parentNode.Nodes.Add(newNode);
else
treeView.Nodes.Add(newNode);
if (!isEmptyElement)
{
parentNode = newNode;
}
}
}
else if (reader.NodeType == XmlNodeType.EndElement)
{
if (reader.Name == XmlNodeTag)
{
parentNode = parentNode.Parent;
}
}
else if (reader.NodeType == XmlNodeType.XmlDeclaration)
{
}
else if (reader.NodeType == XmlNodeType.None)
{
return;
}
else if (reader.NodeType == XmlNodeType.Text)
{
parentNode.Nodes.Add(reader.Value);
}
}
}
finally
{
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:
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;
}
}