Introduction
The AgConfig
class enables binding of any public data member of any object into a control at design time. It automatically handles synchronization between a data member of an object and the contents of a bound control.
It was primarily designed to simplify the work with settings data and creation of settings forms. With this utility class, it is easy to:
- access data in public data members of an object
- bind public data members of an object to controls at design time
- serialize the data to/from an XML file
Background
I was always wondering to have a simple way for creating settings forms and store settings data in a file.
A Control.DataBinding
can be used to bind a control's property to the property of any object. However, this can not be done at design time unless the object is a DataSet
, DataTable
, or a few other classes from System.Data
namespace.
A DataSet
can be easily constructed for any class using Microsoft's XSD utility which is part of VS.NET. This enables us to bind controls to a DataSet
at design time. DataSet
also provides a simple way for storing its contents to an XML file. But accessing DataSet
contents programmatically is a bit more complicated than accessing object's members.
It would be nice to have a tool that automatically synchronizes object data members with the DataSet
contents. So, we could programmatically access our settings through data members of an object and create settings forms easily just by binding the object data members to controls at design time.
Using the code
Usage of the AgConfig
class can be divided into several categories:
- creating a settings class
- creating a
DataSet
from the settings class
- creating a settings form
- reading and writing XML data
1. Creating a settings class
Settings data is represented by public data members of our class, for example the AppData
class, which demonstrates how to create embedded classes to divide settings into sections and also how to create arrays of objects. Note the syntax for creating arrays, the Array
object must be created even empty.
The settings class must have a public default constructor (the one with no arguments) to make it serializable by XmlSelizer
.
public class AppData
{
public string Text = "Hello there";
public int Number = 7;
public class Section1Class
{
public string Text1 = "Hello there 1";
public int Number1 = 77;
}
public Section1Class Section1 = new Section1Class();
public class Item
{
public int ID;
public string Name;
}
public Item[] Items = new Item[] {};
}
Maybe, it is a good idea to put the AppData
class into a separate class library.
2. Creating a DataSet
To create a DataSet
from a settings class, we can use the Microsoft's XSD command line utility which is part of VS.NET. This utility reads the type information from an assembly, so we need to rebuild our project first (ConfigTest).
The command line for the XSL utility looks like follows:
<KBD>xsd configtest.exe /type:AppData</KBD>
After running the above command, a schema0.xsd file containing the XSD schema for AppData
type is created in the current directory. Add this file into the project by clicking the "Project/Add Existing Item..." menu item, and rename it to AppData.xsd for convenience.
Generating DataSet
from this schema can be done by double clicking the AppData.xsd file in Solution Explorer and checking the "Schema/Generate Dataset" menu item.
Finally, the targetNamespace
and id
properties of the created DataSet
must be set to match the way AgConfig
class will handle them. Set the targetNamespace
to "ConfigTest.AppData" (in the form "<application name>.<class name>") and id
to "AppDataDataSet" (in the form "<class name>DataSet").
3. Creating a settings form
The example settings form contains a DataGrid
control which is bound to a AppDataDataSet
component on the form (created by dragging the DataSet
component from the toolbox and selecting the typed AppDataDataSet
). The following code in settings form makes things work together:
private AgConfig AppDataConfig = new AgConfig(Settings.AppData);
Following code is part of the settings form constructor. config1
is initialized so that it automatically reflects changes made in controls bound to appDataDataSet1
into data members of Settings.AppData
(which is a static instance of AppData
class).
AppDataConfig.DataSet = appDataDataSet1;
4. Reading and writing XML data
Settings object data (Settings.AppData
) can be read or written from/to an XML format using several methods provided by AgCondig
class. (See ReadFromXmlxxx()
and WriteToXmlxxx()
methods).
This is an example of serialized XML data:
="1.0"
<AppDataDataSet xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<AppData>
<Text>Hello there</Text>
<Number>7</Number>
<Section1>
<Text1>Hello there 1</Text1>
<Number1>77</Number1>
</Section1>
<Items>
<Item>
<ID>1</ID>
</Item>
<Item>
<ID>2</ID>
</Item>
</Items>
</AppData>
</AppDataDataSet>
Other properties and methods of AgConfig
class are:
XmlExtraTypes
Type
array of additional object types to serialize (see XmlSerializer
constructor for details).
FileName
Fully qualified name of file for storing XML data. By default, this is a file in the application startup directory with the name of Data
object and ".xml" extension.
XmlRootName
Name of the root XML element for serialization. By default, this is the name of Data
object.
XmlNamespace
Target namespace for serialization. By default, this is dot separated application name and Data
object name.
DataSet
A DataSet
associated with this instance. By default, this is an untyped DataSet
with schema inferred from Data
object's XML data.
Data
Actual object that holds settings data.
WriteToXmlFile(string file)
Serializes Data
object data into an XML file.
ReadFromXmlFile(string file)
Deserializes Data
object data from an XML file.
ReadFromXmlStream(Stream s)
Deserializes Data
object data from a stream.
WriteToXmlStream(Stream s)
Serializes Data
object data into a stream.
WriteToDataSet(DataSet ds)
Populates a DataSet
with Data
object data.
ReadFromDataSet(DataSet ds)
Retrieves Data
object data from a DataSet
.
Remarks
Changes made in controls bound to AgConfig.DataSet
are automatically reflected into corresponding AgConfig.Data
object data members.
To reflect changes made directly to AgConfig.Data
object data members into AgConfig.DataSet
, the AgConfig.WriteToDataSet()
method has to be called.
An XmlSerializer
is used to serialize data. Because of this, only public data members are serialized. Some classes from .NET framework library can not be serialized this way. An example of such a class is Drawing.Color
, which has no public data members and hence it can not be serialized using XmlSerializer
. One way to workaround this problem is to create a wrapper class that publishes non-public properties. Another way is to add a new property to settings class that serializes Color
as a string and uses XmlIgnore
and XmlElemrnt
attributes to disable serialization of original property and change the XML element name of the new property.
Points of Interest
The key point was to find out how to serialize an object using XmlSerializer
that it can be deserialized using DataSet.ReadXml()
method and vice versa.
History
This is the initial release.