XML Property Bag
Persist and Restore your data in a manageable, reusable and extensible way with XML
This ActiveX DLL is derived from an excellent original XML PropertyBag sample by Aaron Anderson (Aaron.Anderson@mail.farmcreditbank.com). It allows you to persist and recreate your own objects directly to XML based-files using a simple interface closely related to VB's PropertyBag object. By implementing one interface in your class you will gain the ablility to save state and restore again for any number of objects to and from a single XML file. Full support for binary data means you can store blobs in your XML file too.
The advantages of using XML as a file format for storage in your application cannot be understated (although they probably have by now). XML is plain text. You can read and write XML files by hand (although you might find that a little tedious.) XML is also self-describing. Just looking at an XML file gives you a good idea what it does and it's generally easy to tell how to read the file. On top of that, XML parsers offer three unique features not often seen before the success of the HTTP protocol: they're almost always free, they have a standardised API and they're available for almost any useful computer you can think of.
Anyway, I'm sure you don't need me to tell you that XML is a good idea. Visit Microsoft's XML site for some more ideas and examples!
The XMLPropertyBag object provided with this article comes in two parts: an implementable interface IXMLPropertyBag and a creatable class XMLPropertyBag. To take advantage of the XML Property Bag features, your class should implement the IXMLPropertyBag interface. Doing this effectively adds ReadProperties and WriteProperties events to your object, passing an XMLPropertyBag in as a parameter. The only difference between these events and ones in VB's PropertyBag implementations is that they are prefixed with IXMLPropertyBag_ rather than the base object type name (e.g. UserControl_ ).
Once you have implemented this interface, to provide XML saving and restoring of values can be done in two steps: firstly you write the code in the ReadProperties and WriteProperties methods, and then you write code in the object's owner to initialise reading and writing of values.
Reading and Writing properties is done in almost exactly the same way as with VB's PropertyBag object. The ReadProperty method of the XMLPropertyBag allows you to read the value of a named variant in the property bag and the WriteProperty method does the opposite. The following types of variant can be read and written:
The XMLPropertyBag code will attempt to read/write all other types as a string, but if there is no suitable format available you will get an "Invalid Variant Type" error.
Having implemented these methods, you can then save and restore objects into XML. In the object's owner, create a new instance of the XMLPropertyBag object. If you are saving the object's state, then call the SaveState method on the object, passing in the object to save as the first parameter. You can call SaveState on as many objects as you wish - they will be added to the same XML Document. The optional sName parameter allows you to distinguish between multiple objects of the same type in the same XML file. When complete, you can then get the XML rendering of the objects from the Contents property, which you can then save to whatever storage you are persisting the content to.
To restore objects from the XML, set the Contents property to the saved XML. Then you can call RestoreState, passing in each object you wish to restore (and optionally the name, if you used that).
This discussion demonstrates how you can add persistance to a simple class called in your application. First, assume the class is called cName and has the following definition:
Option Explicit Private m_sFirstName As String Private m_sLastName As String Public Property Get FirstName() As String FirstName = m_sFirstName End Property Public Property Let FirstName(ByVal sName As String) m_sFirstName = sName End Property Public Property Get LastName() As String FirstName = m_sFirstName End Property Public Property Let LastName(ByVal sName As String) m_sLastName = sName End Property
The first step is to implement the IXMLPropertyBag interface. Add this code to the class:
Implements IXMLPropertyBag ... Private Sub IXMLPropertyBag_ReadProperties(ByVal PropertyBag As vbalXMLPBag.XMLPropertyBag) ' End Sub Private Sub IXMLPropertyBag_WriteProperties(ByVal PropertyBag As vbalXMLPBag.XMLPropertyBag) ' End Sub
Now you can fill in your ReadProperties and WriteProperties implementations:
Private Sub IXMLPropertyBag_ReadProperties(ByVal PropertyBag As vbalXMLPBag.XMLPropertyBag) ' FirstName = PropertyBag.ReadProperty("FirstName", "") LastName = PropertyBag.ReadProperty("LastName", "") End Sub Private Sub IXMLPropertyBag_WriteProperties(ByVal PropertyBag As vbalXMLPBag.XMLPropertyBag) ' PropertyBag.WriteProperty "FirstName", FirstName, "" PropertyBag.WriteProperty "LastName", LastName, "" End Sub
Once that is done, you can now save and restore cName objects at will. For example, this code:
Private m_cN As New cName Public Function SaveName() As String ' Create an instance of the XML Property bag object: Dim oP As New XMLPropertyBag ' Save cName into the property bag: oP.SaveState m_cN ' Now the content is saved in the return value: SaveName = oP.Contents End Sub Public Sub RestoreName(ByVal sXML As String) ' Create an instance of the XML Property bag object: Dim oP As New XMLPropertyBag ' Load the XML into it: oP.Contents = sXML ' Restore the object: oP.RestoreState m_cN End Sub
The download code includes a sample demonstrating how to store a Person object which in turn holds a collection of Address objects.