Geeks With Blogs

News
View Szymon Kobalczyk's profile on LinkedIn

Szymon Kobalczyk's Blog A Developer's Notebook
This weekend I've been working on a skin editor for my CustomBorderForms and I wanted to use XML Serialization to store skin files. However, my skins use several System.Drawing classes that don't serialize very cleanly or not at all (e.g. Bitmap, Font, Size) . In such situations I often use surrogate properties that are serialized instead of the original ones. Today I've learned another trick from Load and Save objects to XML using serialization article posted on CodeProject, that shows how to use TypeConverters to simplify serialization of common objects by using TypeDescriptors.

So here is how I serialize a Font property:

[XmlIgnore]
public Font TitleFont
{
    get { return _titleFont; }
    set { _titleFont = value; }
}

[XmlAttribute("titleFont")]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public string TitleFont_XmlSurrogate
{
    get 
    {
        if (TitleFont != null)
        {
            TypeConverter FontConverter = TypeDescriptor.GetConverter(typeof(Font));
            return FontConverter.ConvertToInvariantString(TitleFont);
        } else 
            return null;
    }
    set 
    {
        if (!String.IsNullOrEmpty(value))
        {
            TypeConverter FontConverter = TypeDescriptor.GetConverter(typeof(Font));
            TitleFont = (Font)FontConverter.ConvertFromInvariantString(value);
        }
        else
            TitleFont = null;
    }
}

and the resulting XML element looks like this:

<formStyle titleFont="Tahoma, 8pt, style=Bold" ...>

As you can see, I've added second property, TitleFont_XmlSurrogate to control the serialization and the original property is marked with XmlIgnore. The surrogate property obtains the TypeConverter for serialized type (here Font) and uses its ConvertToInvariantString and ConvertFromInvariantString methods to serialize and derserialize the value of original property. You will want to use InvariantCulture in serialization, because otherwise you can find yourself in troubles in non-English systems. For example, in English systems comma (,) is used as list separators, but in Polish it is serves as digit separator.

Other things to note is that I setup the surrogate property with EditorBrowsable and Browsable attributes so it's not visible and thus not confusing for casual programmer that will be using this classes.

I use the same technique to serialize Size, Padding, Color and other types that can be easily stored as attributes. In case of Bitmaps we can serialize them as arrays of bytes and XmlSerializer will use Base64 encoding to store them (similar to how it works in .resx files). In this case I use MemoryStream to quickly reconstruct the Bitmap from byte array, as shown in the before mentioned article:

[XmlIgnore]
public Bitmap Image
{
    get { return _image; }
    set { _image = value; }
}

[XmlElement("image")]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public byte[] Image_XmlSurrogate
{
    get
    {
        if (Image != null)
        {
            TypeConverter BitmapConverter =
                TypeDescriptor.GetConverter(Image.GetType());
            return (byte[])BitmapConverter.ConvertTo(Image, typeof(byte[]));
        }
        else
            return null;
    }
    set
    {
        if (value != null)
            Image = new Bitmap(new MemoryStream(value));
        else
            Image = null; 
    }
}
Posted on Sunday, May 28, 2006 1:13 PM Development | Back to top


Comments on this post: Using TypeDescriptors for XmlSerialization Surrogates

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © Szymon Kobalczyk | Powered by: GeeksWithBlogs.net