Feedback

Type Color serialisieren und deserialisieren

Sprache: C#

Aus welchem Grund auch immer hat Microsoft für den Typ Color keine Serialisierung implementiert. (Bei anderen struct Typen, wie Point oder Size, die in etwa gleich wichtig und häufig verwendeten werden, haben sie das nicht vergessen) Damit stellt sich das Problem, dass ein Workaround für die De-/Serialisierung verwendet werden muss, damit Farben z.B. in Configurationsdateien abgelegt und wieder eingelesen werden können. Meine Lösung implementiert eine Extension für den Typ string, damit die Farbangaben als Namen wie in der Klasse Color oder als ARGB Wert verwendet werden können. Die Anwendung für ein zu serialisierendes Property in einer Datenstruktur ist sehr simpel und sieht wie folgt aus: [code] [XmlIgnore] public Color MyColor { get; set; } [EditorBrowsable( EditorBrowsableState.Never )] public string MyColorXml { get { return MyColor.Name; } set { MyColor = value.ToColor(); } } [/code]
/// <summary>
/// Returns a <see cref="Color"/> object based on its color name. The 'color name' 
/// is of the color from <see cref="Color.KnownColor"/> or a hexadecimal value as 
/// returned by <see cref="Color.Name"/> (hex format: 'aarrggbb').
/// <para>
/// This can be very easily used, for example, for XML serialisation 
/// where type <see cref="Color"/> can not be used:
/// <pre>
/// [XmlIgnore]
/// public Color MyColor { get; set; }
/// [EditorBrowsable( EditorBrowsableState.Never )]
/// public string MyColorXml
/// {
///     get { return MyColor.Name; }
///     set { MyColor = value.ToColor(); }
/// }
/// </pre>
/// </para>
/// </summary>
/// <returns>A <see cref="Color"/> object.</returns>
public static Color ToColor( this string thisValue )
{
    Color color = Color.FromName( thisValue );
    if( !color.IsKnownColor )
    {
        try
        {
            // try to convert from hex format: aarrggbb
            int iResult = Convert.ToInt32( thisValue, 16 );
            color = Color.FromArgb( iResult >> 24 & 0xff, iResult >> 16 & 0xff, iResult >> 8 & 0xff, iResult & 0xff );
        }
        catch { }
    }
    return color;
}


/// <summary>
/// Returns a <see cref="Color"/> object based on its color name. The 'color name' 
/// is of the color from <see cref="Color.KnownColor"/> or a hexadecimal value as 
/// returned by <see cref="Color.Name"/> (hex format: 'aarrggbb').
/// <para>
/// This can be very easily used, for example, for XML serialisation 
/// where type <see cref="Color"/> can not be used:
/// <pre>
/// [XmlIgnore]
/// public Color MyColor { get; set; }
/// [EditorBrowsable( EditorBrowsableState.Never )]
/// public string MyColorXml
/// {
///     get { return MyColor.Name; }
///     set { MyColor = value.ToColor(); }
/// }
/// </pre>
/// </para>
/// </summary>
/// <returns>A <see cref="Color"/> object.</returns>
public static Color ToColor( this string thisValue )
{
    Color color = Color.FromName( thisValue );
    if( !color.IsKnownColor )
    {
        try
        {
            // try to convert from hex format: aarrggbb
            int iResult = Convert.ToInt32( thisValue, 16 );
            color = Color.FromArgb( iResult >> 24 & 0xff, iResult >> 16 & 0xff, iResult >> 8 & 0xff, iResult & 0xff );
        }
        catch { }
    }
    return color;
}


4 Kommentare

  1. Die Color-Struktur ist mit dem Serializable-Attribut „dekoriert“. Insofern lässt sie sich auch serialisieren/deserialisiern (auch in XML).

    Für die Konvertierung könnte auch ein ColorConverter verwendet werden. Dennoch finde ich die Bitverschiebungen cool 😉

  2. Mit Serializable-Attribute alleine ist noch nicht definiert, dass die Implementierung auch sauber funktioniert.

    Mit folgendem Code wird keine Farbe serialisiert (es entsteht nur ein leeres Tag):
    [code]
    [Serializable]
    public class ABC
    {
    public Color MyColor { get; set; }

    public ABC()
    {
    MyColor = Color.Blue;
    }
    }

    private void Form1_Load( object sender, EventArgs e )
    {
    string strFileName = @“C:tempData.xml“;

    using( TextWriter writer = new StreamWriter( strFileName ) )
    {
    ABC data = new ABC();
    Console.WriteLine( „Before serialization: MyColor = “ + data.MyColor.ToString() );
    XmlSerializer serializer = new XmlSerializer( data.GetType() );
    serializer.Serialize( writer, data );
    }

    using( TextReader reader = new StreamReader( strFileName ) )
    {
    XmlSerializer serializer = new XmlSerializer( typeof( ABC ) );
    ABC data = (ABC)serializer.Deserialize( reader );
    Console.WriteLine( „After serialization: MyColor = “ + data.MyColor.ToString() );
    }
    }
    [/code]

    Die Ausgabe ist dabei:
    [code]Before serialization: MyColor = Color [Blue]
    After serialization: MyColor = Color [Empty]
    [/code]

  3. Das ist nicht weiter verwunderliche, denn die Settings (mit dem Designer) funktionieren ganz anders als die ’normale‘ Serialisierung.