Introduction
About 3 months ago, I was asked to work out a program running on Pocket PC with .NET Compact Framework. It is a program drawing rooms and calculating the geometrical parameters and exporting them to an XML file. The program itself should be able to save the rooms to files and load from them.
Compact FrameWork 2.0 doesn't provide Binary Serialization. And XML Serialization is just too simple to handle what I need: I have to deal with a complex topology of object model. Room A may be associated to Room B, and Room B to Room C, Room C to Room A, it makes a circle finally, just like this:
So, I need a way to serialize such an object model to XML. Fortunately, I had worked out something in my spare time. I call it "xmlable", just like "Serializable" in Binary Serialization.
Using the Code
I will introduce Alex Fr's DrawTools to show you how this has been done.
First, include IXmlabe.cs and Xmlable.cs to your project.
Derive the classes you want to serialize from interface IXmlable, and declare an attribute Xmlable for it, and implement two methods of IXmlable: FromXml and ToXml.
using Xmlable;
using System.Xml;
namespace DrawTools
{
[Xmlable("DrawObject", IsUnique = false)]
abstract class DrawObject : IXmlable
{
public DrawObject(){}
public virtual void FromXml(XmlElement xmlEle, IXmlContext cnt)
{
color = Color.Black;
try { color = Color.FromArgb(Int32.Parse(xmlEle.GetAttribute("color"))); }
catch (Exception) { }
penWidth = 1;
try { penWidth = Int32.Parse(xmlEle.GetAttribute("penWidth")); }
catch (Exception) { }
name = xmlEle.GetAttribute("name");
XmlElement assoEle = xmlEle["associate"];
if(null != assoEle)
{
objAsso = cnt.FromXml(assoEle.FirstChild as XmlElement) as DrawObject;
}
}
public virtual void ToXml(XmlElement xmlEle, IXmlContext cnt)
{
XmlToolkit.SetAttribute(xmlEle, "color", color.ToArgb().ToString());
XmlToolkit.SetAttribute(xmlEle, "penWidth", penWidth.ToString());
XmlToolkit.SetAttribute(xmlEle, "name", name);
XmlElement assoEle = cnt.Document.CreateElement("associate");
XmlElement objEle = cnt.ToXml(objAsso);
if (null != objEle)
assoEle.AppendChild(objEle);
xmlEle.AppendChild(assoEle);
}
}
[Xmlable("TagName", IsUnique = true)]<br />public class ClassA means that
TagName will be the tag name of the XML nodes of the
ClassA, and
IsUnique = true means whatever amount of references of a same object of type
ClassA is serialized into an XML file when the file is loaded, there would not be a lot of references to a lot of different objects.
In order to make DrawTools "Xmlable", the five classes : DrawObject, DrawLine, DrawPolygon, DrawRectangle, DrawEllipse and GraphicsList were modified.
GraphicsList is the container which contains DrawObject, its implementation of IXmlable is as follows:
public virtual void FromXml(XmlElement xmlEle, IXmlContext cnt)
{
graphicsList.Clear();
foreach (XmlElement objEle in xmlEle)
{
DrawObject obj = cnt.FromXml(objEle) as DrawObject;
System.Diagnostics.Debug.Assert(null != obj);
if (null != obj)
{
graphicsList.Add(obj);
}
}
}
public virtual void ToXml(XmlElement xmlEle, IXmlContext cnt)
{
foreach (DrawObject obj in graphicsList)
{
XmlElement objEle = cnt.ToXml(obj);
if (null != objEle)
xmlEle.AppendChild(objEle);
}
}
To save the document of DrawTools, just add some code in MainForm, like this:
Save
private void saveAsXMLToolStripMenuItem_Click(object sender, EventArgs e)
{
if (dlgSave.ShowDialog() != DialogResult.OK)
return ;
XmlDocument doc = new XmlDocument();
IXmlFormatter formatter = FepXmlableFactory.CreateXmlFormatter();
IXmlContext cnt = FepXmlableFactory.CreateXmlContext(formatter, doc);
XmlElement ele = cnt.ToXml(this.drawArea.GraphicsList);
doc.AppendChild(ele);
XmlDeclaration xmldecl;
xmldecl = doc.CreateXmlDeclaration("1.0", null, null);
doc.InsertBefore(xmldecl, doc.DocumentElement);
doc.Save(dlgSave.FileName);
}
Load
private void loadFromXMLToolStripMenuItem_Click(object sender, EventArgs e)
{
if (dlgOpen.ShowDialog() != DialogResult.OK)
return;
XmlDocument doc = new XmlDocument();
doc.Load(dlgOpen.FileName);
IXmlFormatter formatter = FepXmlableFactory.CreateXmlFormatter();
IXmlContext cnt = FepXmlableFactory.CreateXmlContext(formatter, doc);
GraphicsList graphList = cnt.FromXml(doc.DocumentElement) as GraphicsList;
if(null == graphList)
throw new System.IO.IOException(dlgOpen.FileName + " is not a valid file.");
this.drawArea.GraphicsList = graphList;
this.drawArea.Invalidate();
}
Hope This Will Help...
If you are confused by what I have written above, just download the project, run it, draw something, right click on it, set its properties and make them associate with each other. Go to menu "File->Save As XML","File->Load From XML", and open the saved file with text editors to have a look.
I haven't done much testing after I add Xmlable to DrawTools. Let's just focus on how objects are serialized to XML.