ShoaibSivany
ShoaibSivany

Reputation: 43

Getting Serializable Error Even After Inserting [Serializable] Before Class

I created a class

[Serializable]
public class clsCategories
{
    public static List<infoCategories> listCategories = new List<infoCategories>();
    public void serialize()
    {
        BinaryFormatter bf = new BinaryFormatter();
        FileStream fs = new FileStream("categories.dat", FileMode.Create);
        bf.Serialize(fs, listCategories);
        fs.Close();
    }

    [Serializable]
    public class infoCategories
    {
        public PictureBox img { get; set; }
        public Label lbl { get; set; }
    }
}

Now when calling this method...

 private void btnDone_Click(object sender, EventArgs e)
 {
     objCategories.serialize();
     this.Hide();
 }

I got this error:

An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll

Additional information: Type 'System.Windows.Forms.PictureBox' in Assembly 'System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.

Where am i mistaking?

Upvotes: 3

Views: 1763

Answers (2)

Reza Aghaei
Reza Aghaei

Reputation: 125332

It's said in comments and Kuba's answer that PictureBox and Label are not serializable and that's the reason for error. It's not enough to decorate a class with Serializable attribute, all it's properties should be Serializable too.

Instead you can create a class containing a string and an Image and try to serialize it. But unfortunately Image isn't serializable too.

Note: I didn't used Bitmap because the image of PicturebBox maybe a gif or something else.

How Can I serialize a class containing an Image and a string?

For the image, you should serialize it as byte[]. So you can create a class like this:

using System;
using System.Drawing;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable]
public partial class MyData
{
    public string Label { get; set; }
    byte[] bytes;
    [NonSerialized]
    Image image;
    public Image Image
    {
        get
        {
            if (image == null && bytes != null)
                image = (Image)((new ImageConverter()).ConvertFrom(bytes));
            return image;
        }
        set
        {
            image = value;
            bytes = (byte[])new ImageConverter().ConvertTo(value, typeof(byte[]));
        }
    }
}

Then to serialize and deserialize it, you can add a Save and Load method to the class.

public partial class MyData
{
    public void Save(string file)
    {
        using (Stream stream = File.Open(file, FileMode.Create))
        {
            BinaryFormatter bin = new BinaryFormatter();
            bin.Serialize(stream, this);
        }
    }
    public static MyData Load(string file)
    {
        using (Stream stream = File.Open(file, FileMode.Open))
        {
            BinaryFormatter bin = new BinaryFormatter();
            return (MyData)bin.Deserialize(stream);
        }
    }
}

And here is an example usage:

var m1 = new MyData() { Label = label1.Text, Image = pictureBox1.Image };
m1.Save(@"d:\m1.dat");
var m2 = MyData.Load(@"d:\m1.dat");
label2.Text = m2.Label;
pictureBox2.Image = m2.Image;

Upvotes: 2

Kuba Wyrostek
Kuba Wyrostek

Reputation: 6221

When serializing the list of objects of type infoCategories - all properties of these objects are serialized. So is the img property, which happens to be of type PictureBox. Since PictureBox is not serializable itself - you get the error.

The same would happen to Label lbl by the way. No window control can be serialized this way AFAIK.

What are your options?

First: mark all non-serializable fields in your class with [NonSerialized]. This makes the serializer skip the property during read and write. But, since this essentially would lead to an empty class - this is probably not good option here.

Another option is to serialize the very plain data needed to save and restore the objects as you use them. So instead of serializing Label you serialize the string which happens to be this label's text. After deserialization you could recreate a list of labels from the list of strings. The same applies to image contained in picture box (which could be i.e. base64 encoded to string).

The last option is serialization surrogate (Is it possible to do .NET binary serialization of an object when you don't have the source code of the class?) but this would rather be an overkill here.

Upvotes: 4

Related Questions