Save and restore pictures drawn by the user in C#

The example Let the user scribble with different line styles in C# explains how to let the user draw curves with different colors, line thicknesses, and dash patterns. This example adds the ability to save and load pictures drawn by the user.

It turns out, this is remarkably easy. The following code shows how the program saves the Polyline objects stored in the Polylines list.

// Save the drawing.
private void mnuFileSaveAs_Click(object sender, EventArgs e)
{
    if (sfdFile.ShowDialog() == DialogResult.OK)
    {
        XmlSerializer xml_serializer =
            new XmlSerializer(Polylines.GetType());
        using (StreamWriter stream_writer =
            new StreamWriter(sfdFile.FileName))
        {
            xml_serializer.Serialize(stream_writer, Polylines);
            stream_writer.Close();
        }
    }
}

The code displays a SaveFileDialog. If the user selects a file and clicks Save, the program create an XmlSerializer object. It passes the constructor the type of the thing that it will serialize. In this case, that's the data type of the Polylines variable, which is List<Polyline>.

The program then creates a StreamWriter associated with the file. It calls the serializer's Serialize method, passing it the StreamWriter and the object to serialize.

The following code shows how the program deserializes a serialized file.

// Open a saved drawing.
private void mnuFileOpen_Click(object sender, EventArgs e)
{
    if (ofdFile.ShowDialog() == DialogResult.OK)
    {
        try
        {
            XmlSerializer xml_serializer =
                new XmlSerializer(Polylines.GetType());
            using (FileStream file_stream =
                new FileStream(ofdFile.FileName, FileMode.Open))
            {
                List<Polyline> new_polylines =
                    (List<Polyline>)
                        xml_serializer.Deserialize(file_stream);
                Polylines = new_polylines;
                picCanvas.Refresh();
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
}

This code displays a OpenFileDialog. If the user selects a file and clicks Open, the program again creates an XmlSerializer for the Polylines type.

Next the program creates a FileStream associated with the file, opening it as it creates the FileStream.

The code then calls the serializer's Deserialize method. The result is a generic object, so the program casts it to the List<Polyline> type. It finally saves the result in the variable Polylines and refreshes the drawing PictureBox.

If those were the only changes you made, you would be able to save and restore Polylines, but they would be missing their Color properties. It turns out, that all of the other properties of the Polyline class (int, DashStyl, and even List<Point>) all serialize automatically, but the Color class does not. That means when you serialize a list of Polylines, their colors are not saved. When you reload a file, the program draws the Polylines, but you don't see them because their colors are not reloaded.

The workaround is to create a property that represents Color but that can be serialized. This example uses a property named Argb that gets and sets the color's alpha, red, green, and blue color components as a combined integer. An integer can serialize automatically so the program works.

To avoid a bit of wasted effort, the program also flags the Color property with the XmlIgnore attribute so the serializer ignores it completely.

The following shows the revised Polyline class.

public class Polyline
{
    [XmlIgnore] public Color Color = Color.Black;
    public int Thickness = 1;
    public DashStyle DashStyle = DashStyle.Solid;
    public List<Point> Points = new List<Point>();

    // Get or set the color as an ARGB value.
    public int ToArgb
    {
        get { return this.Color.ToArgb(); }
        set { Color = Color.FromArgb(value); }
    }

    public void Draw(Graphics gr)
    {
        using (Pen the_pen = new Pen(Color, Thickness))
        {
            the_pen.DashStyle = DashStyle;
            if (DashStyle == DashStyle.Custom)
            {
                the_pen.DashPattern = new float[] { 10, 2 };
            }
            gr.DrawLines(the_pen, Points.ToArray());
        }
    }
}

The Argb property's get method returns the value represented by the Color property, and its set method uses an integer to set the object's Color property.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in drawing, graphics, serialization and tagged , , , , , , , , , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

3 Responses to Save and restore pictures drawn by the user in C#

  1. Richard Moss says:

    “The example Display an end user license agreement the first time the user runs a program in C# explains how to let the user draw curves”

    Erm… it does?

  2. Rod Stephens says:

    Oops! I’ve fixed that reference. Thanks for pointing this out.

  3. Pingback: Provide undo and redo in C# - C# HelperC# Helper

Leave a Reply

Your email address will not be published. Required fields are marked *