views:

337

answers:

5

The classSystem.Drawing.Font is not XML Serializable since it doesn't have a default (empty) constructor.
Is there some work around or alternative way to serialize Font nevertheless?

+4  A: 

A suggestion on how to do this by implementing a wrapper class that is serializable is given on the MSDN page for the Font class.

Håvard S
Yes - a wrapper around the class that is genuinely xml serializable is the way to go IMHO
Rob Levine
+3  A: 

Edit: I updated the code according to Regent suggestion to use FontConverter, while preserving the ability to use the SerializableFont as regular Font.

public class SerializableFont
{
    public SerializableFont()
    {
        FontValue = null;
    }

    public SerializableFont(Font font)
    {
        FontValue = font;
    }

    [XmlIgnore]
    public Font FontValue { get; set; }

    [XmlElement("FontValue")]
    public string SerializeFontAttribute
    {
        get
        {
            return FontXmlConverter.ConvertToString(FontValue);
        }
        set
        {
            FontValue = FontXmlConverter.ConvertToFont(value);
        }
    }

    public static implicit operator Font(SerializableFont serializeableFont)
    {
        if (serializeableFont == null )
            return null;
        return serializeableFont.FontValue;
    }

    public static implicit operator SerializableFont(Font font)
    {
        return new SerializableFont(font);
    }
}

public static class FontXmlConverter
{
    public static string ConvertToString(Font font)
    {
        try
        {
            if (font != null)
            {
                TypeConverter converter = TypeDescriptor.GetConverter(typeof(Font));
                return converter.ConvertToString(font);
            }
            else 
                return null;
        }
        catch { System.Diagnostics.Debug.WriteLine("Unable to convert"); }
        return null;
    }
    public static Font ConvertToFont(string fontString)
    {
        try
        {
            TypeConverter converter = TypeDescriptor.GetConverter(typeof(Font));
            return (Font)converter.ConvertFromString(fontString);
        }
        catch { System.Diagnostics.Debug.WriteLine("Unable to convert"); }
        return null;
    }
}

Usage: When you have a Font property, declare it as SerializableFont. This will allow it to be serialized, while the implicit cast will handle the conversion for you.

Instead of writing:

Font MyFont {get;set;}

Write:

SerializableFont MyFont {get;set;}
Elad
Strictly speaking you have ended up with some xml, but in reality you've eliminated all the semantic richness of xml by just dumping its binary contents in a base64 encoded text element. IMHO It's really not "xml serialized" in the useful sense of the word.It's not like you can "see" any of the Font properties in the xml, without deserializing first, nor can you XPath it, transform it, iterate over it, etc
Rob Levine
A: 

Try the DataContractSerializer.

        Font fnt = new Font("Arial", 1);
        MemoryStream data = new MemoryStream();
        DataContractSerializer dcs = new DataContractSerializer(typeof(Font), new[] { typeof(FontStyle), typeof(GraphicsUnit) });
        dcs.WriteObject(data, fnt);
        string xml = Encoding.UTF8.GetString(data.ToArray());
Mikael Svenson
A: 

System.Drawing.Font have an associated FontConverter class and I would manually converting it:

[Serializable]
public class SerializableFont
{
    public SerializableFont()
    {
        this.Font = null;
    }

    public SerializableFont(Font font)
    {
        this.Font = font;
    }

    [XmlIgnore]
    public Font Font { get; set; }

    [XmlElement("Font")]
    public string FontString
    {
        get
        {
            if (font != null)
            {
                TypeConverter converter = TypeDescriptor.GetConverter(typeof(Font));

                return converter.ConvertToString(this.Font);
            }
            else return null;
        }
        set
        {
            TypeConverter converter = TypeDescriptor.GetConverter(typeof(Font));

            this.Font = converter.ConvertFromString(value);
        }
    }
}
Regent
A: 

I use a serializable font, somewhat different from Elad's.

In my serializable data-entities I hide ([XmlIgnore]) the property with the Font type and expose the property with the SerializableFont type, which is "eaten" by the serializer.

Note that this is applicable to the XmlSerializer only.

/// <summary>
/// Font descriptor, that can be xml-serialized
/// </summary>
public class SerializableFont
{
    public string FontFamily { get; set; }
    public GraphicsUnit GraphicsUnit { get; set; }
    public float Size { get; set; }
    public FontStyle Style { get; set; }

    /// <summary>
    /// Intended for xml serialization purposes only
    /// </summary>
    private SerializableFont() { }

    public SerializableFont(Font f)
    {
        FontFamily = f.FontFamily.Name;
        GraphicsUnit = f.Unit;
        Size = f.Size;
        Style = f.Style;
    }

    public static SerializableFont FromFont(Font f)
    {
        return new SerializableFont(f);
    }

    public Font ToFont()
    {
        return new Font(FontFamily, Size, Style,
            GraphicsUnit);
    }
}
Yacoder