|
using System;
using System.Data;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Windows.Forms;
using System.Reflection;
using System.Collections;
namespace AG1206
{
/// <summary>
/// Simple object XML serializing and support for binding object instance members
/// directly to data bound contorls, with automatic reflection of changes made to
/// data bound controls to corresponding instance members.
/// </summary>
public class AgConfig
{
/// <summary>
/// Initializes a new instance.
/// </summary>
public AgConfig()
{
Data = new object();
}
/// <summary>
/// Initializes a new instance, and specifies the Data object and DataSet.
/// </summary>
/// <param name="data">The data object to use</param>
public AgConfig(object data)
{
Data = data;
}
#region Properties...
private string _FileName;
private DataSet _DataSet;
private string _XmlRootName;
private string _XmlNamespace;
private Object _Data;
/// <summary>
/// A Type array of additional object types to serialize.
/// </summary>
public Type[] XmlExtraTypes;
/// <summary>
/// Gets or stets the XML file for serialization.
/// </summary>
/// <remarks>
/// By default, this is a file located in the application startup directory with
/// the same name as the Data object and with the extension ".xml".
/// </remarks>
public string FileName { set { _FileName = value; } get { return _FileName; } }
/// <summary>
/// Gets or stets a DataSet associated with this instance.
/// </summary>
/// <remarks>
/// DataSet can be used for binding Data members directly to data bound controls.
/// When the contents of a data bound control is changed, the change is
/// automatically reflected to the corresponding instance member.
/// </remarks>
public DataSet DataSet
{
set
{
_DataSet = value;
if(_DataSet != null)
{
_DataSet.DataSetName = XmlRootName + "DataSet";
_DataSet.Namespace = XmlNamespace;
WriteToDataSet();
}
}
get
{
if(_DataSet != null)
return _DataSet;
DataSet = new DataSet();
return _DataSet;
}
}
/// <summary>
/// Gets or sets the name of the root XML elemtnt for serialization.
/// </summary>
/// <remarks>
/// By default, this is the same as the nama of Data object.
/// </remarks>
public string XmlRootName { set { _XmlRootName = value; } get { return _XmlRootName; } }
/// <summary>
/// Gets or sets the XML namespace for serialization.
/// </summary>
/// <remarks>
/// By default, this is in the form "Application name"."Data object name".
/// </remarks>
public string XmlNamespace { set { _XmlNamespace = value; } get { return _XmlNamespace; } }
/// <summary>
/// Data object
/// </summary>
public Object Data { get { return _Data; } set { _Data = value; Initialize(); } }
#endregion
/// <summary>
/// Serializes Data into XML file.
/// </summary>
public void WriteToXmlFile()
{
WriteToXmlFile(FileName);
}
/// <summary>
/// Serializes Data into XML file, and specifies file to use.
/// </summary>
/// <param name="file">File to use</param>
public void WriteToXmlFile(string file)
{
Stream s = File.Open(file, FileMode.Create);
using(s) XmlSerializer.Serialize(s, Wrapper);
}
/// <summary>
/// Deserializes Data from XML file.
/// </summary>
public void ReadFromXmlFile()
{
ReadFromXmlFile(FileName);
}
/// <summary>
/// Deserializes Data from XML file, and specifies file to use.
/// </summary>
/// <param name="file">File to use</param>
public void ReadFromXmlFile(string file)
{
Object data;
if(File.Exists(file))
{
Stream s = File.Open(file, FileMode.Open);
DataWrapper wr;
using(s) wr = (DataWrapper)XmlSerializer.Deserialize(s);
data = wr.Root;
}
else
{
data = Activator.CreateInstance(Data.GetType());
}
AssignData(data);
WriteToDataSet();
}
/// <summary>
/// Deserializes Data from stream, and specifies stream to use.
/// </summary>
/// <param name="s">Stream to use</param>
public void ReadFromXmlStream(Stream s)
{
ReadFromXmlStreamInternal(s);
WriteToDataSet();
}
/// <summary>
/// Serializes Data to stream, and specifies stream to use.
/// </summary>
/// <param name="s">Stream to use</param>
public void WriteToXmlStream(Stream s)
{
XmlSerializer.Serialize(s, Wrapper);
}
/// <summary>
/// Serializes Data into DataSet.
/// </summary>
public void WriteToDataSet()
{
WriteToDataSet(DataSet);
}
/// <summary>
/// Serializes Data into DataSet, and specifies DataSet to use.
/// </summary>
/// <param name="ds">DataSet to use</param>
public void WriteToDataSet(DataSet ds)
{
MemoryStream s = new MemoryStream();
WriteToXmlStream(s);
s.Seek(0, SeekOrigin.Begin);
ds.Clear();
bool containsData = (ds.Tables.Count > 0);
try
{
LockUpdates = true;
ds.ReadXml(s, containsData ? XmlReadMode.IgnoreSchema : XmlReadMode.InferSchema);
}
finally
{
LockUpdates = false;
}
foreach(DataTable table in ds.Tables)
{
table.RowDeleted += new DataRowChangeEventHandler(OnTableDataRowDeleted);
table.RowChanged += new DataRowChangeEventHandler(OnTableDataRowChanged);
table.ColumnChanged += new DataColumnChangeEventHandler(OnTableDataColumnChanged);
}
}
/// <summary>
/// Deserializes Data from DataSet, and specifies DataSet to use.
/// </summary>
/// <param name="ds">DataSet to use</param>
public void ReadFromDataSet(DataSet ds)
{
MemoryStream s = new MemoryStream();
ds.WriteXml(s, XmlWriteMode.IgnoreSchema);
s.Seek(0, SeekOrigin.Begin);
ReadFromXmlStreamInternal(s);
}
/// <summary>
/// Writes XML schema into file.
/// </summary>
/// <remarks>
/// The target file is FileName with an extension ".xsd".
/// </remarks>
public void WriteSchemaToFile()
{
WriteSchemaToFile(FileName);
}
/// <summary>
/// Writes XML schema into file, and specifies file to use.
/// </summary>
/// <remarks>
/// The target file always has an extension ".xsd".
/// </remarks>
/// <param name="file">File to use</param>
public void WriteSchemaToFile(string file)
{
DataSet ds = DataSet;
Stream s = File.Open(Path.ChangeExtension(file, ".xsd"), FileMode.Create);
using(s) ds.WriteXmlSchema(s);
}
#region Private code...
/// <summary>
/// Internal wrapper class. Must have public access.
/// </summary>
public class DataWrapper
{
/// <summary>
/// Internal wrapper member.
/// </summary>
public Object Root;
}
private bool LockUpdates = false;
private XmlSerializer _XmlSerializer = null;
private XmlSerializer XmlSerializer { get { return _XmlSerializer; } }
private void OnTableDataRowChanged(object sender, DataRowChangeEventArgs e)
{
if(!LockUpdates)
{
ReadFromDataSet(DataSet);
}
}
private void OnTableDataColumnChanged(object sender, DataColumnChangeEventArgs e)
{
if(!LockUpdates)
{
ReadFromDataSet(DataSet);
}
}
private void OnTableDataRowDeleted(object sender, DataRowChangeEventArgs e)
{
DataTable table = (DataTable)sender;
if(!LockUpdates)
{
if(e.Action == DataRowAction.Delete)
table.AcceptChanges();
ReadFromDataSet(DataSet);
}
}
private DataWrapper Wrapper = new DataWrapper();
private void Initialize()
{
FileName = Path.Combine(Application.StartupPath, Path.ChangeExtension(Data.GetType().Name, ".xml"));
XmlRootName = Data.GetType().Name;
XmlNamespace = "";
_XmlSerializer = CreateXmlSerializer();
}
private XmlSerializer CreateXmlSerializer()
{
Wrapper.Root = Data;
XmlRootAttribute xmlRoot = new XmlRootAttribute(XmlRootName + "DataSet");
xmlRoot.Namespace = XmlNamespace;
XmlAttributes attrs = new XmlAttributes();
XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
attrs.XmlElements.Add(new XmlElementAttribute(XmlRootName, Data.GetType()));
attrOverrides.Add(Wrapper.GetType(), "Root", attrs);
int extraTypesLength = (XmlExtraTypes == null) ? 0 : XmlExtraTypes.Length;
Type[] types = new Type[extraTypesLength + 1];
types[0] = Data.GetType();
if(extraTypesLength > 0)
XmlExtraTypes.CopyTo(types, 1);
return new XmlSerializer(Wrapper.GetType(), attrOverrides, types, xmlRoot, XmlNamespace);
}
private void AssignData(Object other)
{
Type type = Data.GetType();
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public;
FieldInfo[] fields = type.GetFields(flags);
foreach(FieldInfo fi in fields)
fi.SetValue(Data, fi.GetValue(other));
}
private void ReadFromXmlStreamInternal(Stream s)
{
Object data;
DataWrapper wr = (DataWrapper)XmlSerializer.Deserialize(s);
data = wr.Root;
AssignData(data);
}
#endregion
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.