0

Any event handlers marked as [NonSerialized] get destroyed on deserialization, so you need to manually re-hook all the required event handlers to the deserialized object after deserialization [Binary]. The only problem is, I don't know how to do that. Any help?

My serializable class:

[Serializable]
public class DownloadEntry : INotifyPropertyChanged
{
    [field: NonSerialized]
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public string DownloadID { get; set; }
    public Uri DownloadLink { get; set; }
    public string FileName { get; set; }
    private long size;
    public long Size
    {
        get { return size; }
        set
        {
            size = value;
            OnPropertyChanged("Size");
        }
    }
    public string SizePretty
    {
        get
        {
            return Helper.SizeSuffix(Size);
        }
        set
        {
            SizePretty = Size.ToString();
        }
    }
    private string timeleft;
    public string TimeLeft
    {
        get { return timeleft; }
        set
        {
            timeleft = value;
            OnPropertyChanged("TimeLeft");
        }
    }
    private string status;
    public string Status
    {
        get { return status; }
        set
        {
            status = value;
            OnPropertyChanged("Status");
        }
    }
    private string transferrate;
    public string TransferRate
    {
        get { return transferrate; }
        set
        {
            transferrate = value;
            OnPropertyChanged("TranferRate");
        }
    }
    public DateTime DateAdded { get; set; }
    public DateTime LastTryDate { get; set; }
    public string SaveTo { get; set; }
    public string Q { get; set; }
    public string Description { get; set; }
    public string AuthUsername { get; set; }
    public string AuthPassword { get; set; }
    public string ObtainedFrom { get; set; }
    [NonSerialized]
    private bool running;
    public bool Running 
    { 
        get { return running; } 
        set 
        { 
            running = value;
            OnPropertyChanged("Running");
        }
    }
}

Class where serialization and deserialization takes place:

public static class Downloads
{
    public static ObservableCollection<DownloadEntry> DownloadEntries = new ObservableCollection<DownloadEntry>();

    public static void Deserialize()
    {
        if (File.Exists("downloads.dat"))
        {
            IFormatter formatter = new BinaryFormatter();
            using (FileStream stream = File.OpenRead("downloads.dat"))
            {
                DownloadEntries = (ObservableCollection<DownloadEntry>)formatter.Deserialize(stream);
            }
        }
    }

    public static void Serialize()
    {
        IFormatter formatter = new BinaryFormatter();
        using (FileStream stream = File.Create("downloads.dat"))
        {
            formatter.Serialize(stream, DownloadEntries);
        }
    }
}

What I found on here, but there were no explanations on how to do it.

https://stackoverflow.com/a/6697942/4932305 :

most of my implementations of INotifyPropertyChanged I explicitly mark the PropertyChanged event as being non-serialized and then manually re-hook the event upon deserialization as appropriate.

Code present but it's in VB.net: Events not working with after Deserialization :

The problem is not that the Changed event isn't being fired; as long as the same class definition (with the setter that raises the event) is used for the deserialized object (with DataContract serialization that isn't a requisite), the event will be raised. What's happening is that the deserialized object no longer has the handler attached.

You cannot serialize or deserialize event handlers; at the very least, you shouldn't. Because they may point to references other than the current object reference, and because the deserialized object is a new reference in what is probably a different runtime, event handler references from the serialized object are useless on deserialization, because the reference will no longer point to the expected object in the new runtime's heap.

Community
  • 1
  • 1
Expenzor
  • 432
  • 1
  • 5
  • 17

2 Answers2

0

You have to implement your static class to Deserialized it using the serialized contents (xml or binary) and subscribe to required events.

public static DownloadEntry Deserialize(string serializedXmlContents) 
{
    DownloadEntry downloadEntry= ... // Do the deserialization
    // Subscribe to your events
    return downloadEntry;
}
CharithJ
  • 46,289
  • 20
  • 116
  • 131
0

The solution is here: http://web.archive.org/web/20150531190503/http://www.gavaghan.org/blog/2007/07/20/demonstrating-bindinglist-serialization-bug/

Because I couldn't apply it to my ObservableCollection. I just used a BindingList, which acts pretty much the same as an ObservableCollection. All I had to do was change CollectionChanged event to ListChanged and my problem was solved.

I have spent days obsessing over this. Thankfully, that's over now.

Expenzor
  • 432
  • 1
  • 5
  • 17