65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 XmlTextWriter 和 XmlTextReader 将 TreeView 控件加载和保存到 XML 文件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.74/5 (53投票s)

2006 年 2 月 17 日

CPOL

4分钟阅读

viewsIcon

236563

downloadIcon

15162

演示如何使用单向、非缓存的 XmlTextReader 和 XmlTextWriter 从 XML 文件中序列化和反序列化 System.Windows.Forms.TreeView 控件的内容。

引言

本文的目的是演示如何将 System.Windows.Forms.TreeView 控件的内容保存到 XML 文件以及从 XML 文件加载。System.Xml 命名空间中的 XmlTextReaderXmlTextWriter 分别用于读取和生成 XML 文件。它还使用 TreeView 控件演示了一个简单的 XML 文件查看器。

入门

实际功能包含在一个名为 TreeViewSerializer 的类中。它有两个主要职责:

  1. TreeView 保存到指定的 XML 文件。
  2. 从任何指定的 XML 文件加载 TreeView

用于序列化 TreeView 的 XML 文件的结构非常简单。以下是随附项目包含的示例 XML 文件:

<?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>

在 XML 声明之后,所有节点都包含在 TreeView 标签中。TreeView 标签可以包含多个 node 标签。node 标签也可以包含其他 node 标签。每个 node 标签可以有三个属性:

  1. 文本
  2. ImageIndex
  3. Tag

我已经序列化了 System.Windows.Forms.TreeNode 对象的上述三个属性,可以轻松扩展以包含其他属性。

XmlNodeTagXmlNodeTextAttXmlNodeTagAttXmlNodeImageIndexAtt 是在 TreeViewSerializer 类中定义的常量。

// 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";

从 XML 加载 TreeView – 反序列化

反序列化由 DeserializeTreeView 方法执行,该方法使用 XmlTextReader 解析 XML 文档并填充 TreeView 对象。以下是 DeserializeTreeView 方法的定义:

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(); 
   }
}

XmlTextReader 解析 XML 文档时,会根据 NodeType 采取适当的操作。如果 NodeTypeElement,则会创建一个新的 TreeNode,并使用 XML 节点属性设置其属性。对于非空元素,将 ParentNode 设置为新的 TreeNode,以便对其子节点进行反序列化。如果遇到 EndElement,则将 ParentNode 设置为当前父节点的父节点,表示当前节点的子节点已全部反序列化。

为了设置 TreeNodeTextTagImageIndex 属性,会调用 SetAttributeValue 方法。其实现如下:

  /// <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;
       }  
  }

保存 TreeView – 序列化

SerializeTreeViewSystem.Windows.Forms.TreeView 保存到指定的文件。以下是方法定义:

public void SerializeTreeView(TreeView treeView, string fileName) 
  {
       XmlTextWriter textWriter = new XmlTextWriter(fileName, 
                                     System.Text.Encoding.ASCII);
       // writing the xml declaration tag

       textWriter.WriteStartDocument();
       //textWriter.WriteRaw("\r\n");

       // writing the main tag that encloses all node tags

       textWriter.WriteStartElement("TreeView");
       
       // save the nodes, recursive method

       SaveNodes(treeView.Nodes, textWriter);
       
       textWriter.WriteEndElement();
         
       textWriter.Close();
  }

我猜上面的代码是相当不言自明的。SerializeTreeView 方法:

  1. 实例化 XmlTextWriter,并将提供的文件名传递给它。
  2. XML 声明 (<?xml version="1.0" encoding="us-ascii" ?>) 被写入流。
  3. TreeView 标签被写入流。
  4. 调用 SaveNodes 方法。将 TreeView 中的 TreeNode 集合传递给它,它通过递归调用自身将 TreeView 中的所有节点保存到流中。其定义如下所示。
  5. 写入 TreeView 的结束标签。
  6. 最后,关闭流。

以下是 SaveNodes 方法的定义:

private void SaveNodes(TreeNodeCollection nodesCollection, 
   XmlTextWriter textWriter)
  {
       for(int i = 0; i < nodesCollection.Count; i++)
       {
            TreeNode node = nodesCollection[i];
            textWriter.WriteStartElement(XmlNodeTag);
            textWriter.WriteAttributeString(XmlNodeTextAtt, 
                                                       node.Text);
            textWriter.WriteAttributeString(
                XmlNodeImageIndexAtt, node.ImageIndex.ToString());
            if(node.Tag != null) 
                 textWriter.WriteAttributeString(XmlNodeTagAtt, 
                                             node.Tag.ToString());
            // add other node properties to serialize here  

            if (node.Nodes.Count > 0)
            {
                 SaveNodes(node.Nodes, textWriter);
            }     
            textWriter.WriteEndElement();
       }
  }

SaveNodes 方法循环遍历 TreeNode 集合,并写入 node 标签及其属性。如果一个 node 包含子节点,则递归调用该方法。在方法返回后(已将子节点写入流),写入节点的结束标签。

XML 文件查看器

TreeViewSerializer 类中还有另一个名为 LoadXmlFileInTreeView 的方法。该方法可用于在 TreeView 中查看任何 XML 文档。以下屏幕截图显示了加载到 TreeView 中的示例 XML 文件:

加载 XML 文件的代码与 SerializeTreeView 方法非常相似。为简洁起见,此处不包含代码。您可以在附件的源代码中找到它。

演示应用程序

本文提供了一个演示应用程序,作为 TreeViewSerializer 功能的驱动程序。它有三个功能:

  • 保存:将 TreeView 保存/序列化到 XML 文件。会出现一个 SaveFileDialog 用于指定文件。
  • 加载:从 XML 文件加载/反序列化 TreeView
  • 查看 XML 文件:在 TreeView 中查看任何 XML 文件。

注释

XML 文档也可以使用基于 DOM 的 XmlDocumentXmlNode 类进行操作。如果我们还需要搜索和编辑 XML 文档,它们会很有用。在我们的例子中,XmlTextWriterXmlTextReader 更高效,因为它们以单向、非缓存的方式运行。

生成的 XML 文件**不会**通过插入换行符和制表符进行格式化。为此,请在 SerializeTreeView 的适当位置使用 textWriter.WriteRaw("\r\n);。当然,您可以使用 IE 查看格式化的 XML 文件。 :)

© . All rights reserved.