65.9K
CodeProject is changing. Read more.
Home

TreeView with XML

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.08/5 (6 votes)

Jun 19, 2007

CPOL

2 min read

viewsIcon

33446

downloadIcon

1449

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:

  1. Saving the TreeView to a specified XML file.
  2. 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:

  1. Text
  2. ImageIndex
  3. 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;
   }  
}