none
How to Serialize a Class with a Property Which Is an ObservableCollection of Itself

    Question

  • The followings are my code:

    Code for serialization:

    public class Serializer
    {
       
    public Serializer()
       
    {
       
    }

       
    public void SerializeObject(string filename, ObjectToSerialize objectToSerialize)
       
    {
         
    Stream stream = File.Open(filename, FileMode.Create);
         
    BinaryFormatter bFormatter = new BinaryFormatter();
          bFormatter
    .Serialize(stream, objectToSerialize);
          stream
    .Close();
       
    }

       
    public ObjectToSerialize DeSerializeObject(string filename)
       
    {
         
    ObjectToSerialize objectToSerialize;
         
    Stream stream = File.Open(filename, FileMode.Open);
         
    BinaryFormatter bFormatter = new BinaryFormatter();
          objectToSerialize
    = (ObjectToSerialize)bFormatter.Deserialize(stream);
          stream
    .Close();
         
    return objectToSerialize;
       
    }
    }



     

    [Serializable()]
    public class ObjectToSerialize : ISerializable 
    {
        private Sheet sheet;
    

    public Sheet Sheet { get { return this.sheet; } set { this.sheet = value; } } public ObjectToSerialize() { } public ObjectToSerialize(SerializationInfo info, StreamingContext ctxt) { this.sheet = (Sheet)info.GetValue("Sheet", typeof(Sheet)); } public void GetObjectData(SerializationInfo info, StreamingContext ctxt) { info.AddValue("Sheet", this.sheet); }
    }



    My classes for my objects:

    [Serializable()]  
    public class Sheet : ISerializable  
    {  
       
    //Some other properties for a sheet shuch as width, length, x, y

       
    //An observable list is used to store all sub-sheets in a sheet
       
    private SheetStack subSheets;

       
    public SheetStack SubSheets
       
    {
           
    get {return this.subSheets;}
           
    set {this.subSheets = value;}
       
    }

       
    public Sheet(SerializationInfo info, StreamingContext ctxt)  
       
    {  
           
    this.subSheets = (SheetStack)info.GetValue("SubSheets", typeof(SheetStack));
       
    }  

       
    public void GetObjectData(SerializationInfo info, StreamingContext ctxt)  
       
    {  
            info
    .AddValue("SubSheets", this.subSheets);
       
    }
    }

    [Serializable()]  
    public class  SheetStack : ObservableCollection<Sheet>, ISerializable
    {
       
    //No real properties for a sheet stack but some methods such as:
       
    //PopOneSheet( )
       
    //PushOneSheet( )
       
    //RotateAllSheets()
    public Sheet(SerializationInfo info, StreamingContext ctxt)  
       
    {  
           
    //What should I put here?  
    }  

       
    public void GetObjectData(SerializationInfo info, StreamingContext ctxt)  
       
    {  
            //What should I put here?  

       
    }


    }
    My problem is that I can serialize a Sheet object and save data to a file. But when I de-serialize it, Sheet.SubSheets is empty.

    EyesBoard - A cool software keyboard which looks and behaves like a physical keyboard
    Tuesday, December 01, 2009 11:22 AM

Answers

  • Your problem now is the subscription.  You'll have to explicitly implement the event using the add and remove methods, leaving a delegate as a field in the sheet class that can be marked with XmlIgnore, so you don't serialize your event. 

    Note that reconstituting the object from a stream won't re-attach your events, so you'll have to do that manually as well.

    Here's a brief example:

        class NotSerializable
        {
            public void Subscribe(Serializable serializable)
            {
                serializable.Event += new EventHandler(serializable_Event);
            }

            void serializable_Event(object sender, EventArgs e)
            {
                Console.WriteLine("Hey!");
            }
        }

        [Serializable]
        class Serializable
        {
            [NonSerialized] // Don't serialize this delegate, as it may contain a reference to something not serializable.
            private EventHandler _delegate;

            public event EventHandler Event
            {
                add { _delegate = (EventHandler)Delegate.Combine(_delegate, value); }
                remove
                {
                    if (_delegate != null)
                        _delegate = (EventHandler)Delegate.Remove(_delegate, value);
                }
            }
        }

        class Program
        {
            static void Main(string[] args)
            {
                Serializable ser = new Serializable();
                NotSerializable notSer = new NotSerializable();
                notSer.Subscribe(ser);

                BinaryFormatter formatter = new BinaryFormatter();
                MemoryStream stream = new MemoryStream();
                formatter.Serialize(stream, ser);

            }
        }


    Coding Light - Illuminated Ideas and Algorithms in Software
    Coding Light WikiLinkedInForumsBrowser
    • Marked as answer by Scott Chiu Thursday, December 03, 2009 4:29 AM
    Tuesday, December 01, 2009 3:35 PM

All replies

  • You don't have to do anything.  Remove your entire implementation of ISerializable and try again.  Since you're using a BinaryFormatter, there's no reason to implement ISerializable.  You have no custom work to do here. 


    Coding Light - Illuminated Ideas and Algorithms in Software
    Coding Light WikiLinkedInForumsBrowser
    Tuesday, December 01, 2009 12:02 PM
  • Hi David:

    Thank you for your suggestion.

    I've removed all my implemention of ISerializable but encountered another problem during serialization.

    In my Sheet class, INotifyPropertyChanged was implemented so that a related UserControl named SheetControl could be notified when Sheet is changed.

    Even I also marked UserControl as serializable, the following error occurred:

    System.Runtime.Serialization.SerializationException was unhandled
      Message="Type 'System.Windows.Controls.UserControl' in Assembly 'PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' is not marked as serializable."
      Source="mscorlib"
      StackTrace:
      ......
      ......
      ......

    EyesBoard - A cool software keyboard which looks and behaves like a physical keyboard
    Tuesday, December 01, 2009 3:24 PM
  • Your problem now is the subscription.  You'll have to explicitly implement the event using the add and remove methods, leaving a delegate as a field in the sheet class that can be marked with XmlIgnore, so you don't serialize your event. 

    Note that reconstituting the object from a stream won't re-attach your events, so you'll have to do that manually as well.

    Here's a brief example:

        class NotSerializable
        {
            public void Subscribe(Serializable serializable)
            {
                serializable.Event += new EventHandler(serializable_Event);
            }

            void serializable_Event(object sender, EventArgs e)
            {
                Console.WriteLine("Hey!");
            }
        }

        [Serializable]
        class Serializable
        {
            [NonSerialized] // Don't serialize this delegate, as it may contain a reference to something not serializable.
            private EventHandler _delegate;

            public event EventHandler Event
            {
                add { _delegate = (EventHandler)Delegate.Combine(_delegate, value); }
                remove
                {
                    if (_delegate != null)
                        _delegate = (EventHandler)Delegate.Remove(_delegate, value);
                }
            }
        }

        class Program
        {
            static void Main(string[] args)
            {
                Serializable ser = new Serializable();
                NotSerializable notSer = new NotSerializable();
                notSer.Subscribe(ser);

                BinaryFormatter formatter = new BinaryFormatter();
                MemoryStream stream = new MemoryStream();
                formatter.Serialize(stream, ser);

            }
        }


    Coding Light - Illuminated Ideas and Algorithms in Software
    Coding Light WikiLinkedInForumsBrowser
    • Marked as answer by Scott Chiu Thursday, December 03, 2009 4:29 AM
    Tuesday, December 01, 2009 3:35 PM
  • Hi David:

    It works.
    Thank you very much.

    Scott


    EyesBoard - A cool software keyboard which looks and behaves like a physical keyboard
    Thursday, December 03, 2009 4:29 AM