简体   繁体   中英

Why my ObservableCollection serialization doesn't work?

I'm trying to serialize and deserialize this ObservableCollection:

public class DataCollection : ObservableCollection<Data>
{
}

public class Data : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private bool? _enabled;

    public string Name { get; set; }
    public bool? Enabled 
    {
        get { return _enabled; }
        set { _enabled = value; NotifyPropertyChanged("Enabled"); }
    }

    public Data(string name, bool? enabled)
    {
        this.ScriptName = name;
        this.Enabled = enabled;
    }

    private void NotifyPropertyChanged(string property)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }
}

Using this class (as in the What is the easiest way to save an Observable collectin of object to an XML file? example):

class UserPreferences
{
    private DataCollection _dataLst;
    private const string _dataLstFileName = "Data.xml";

    public DataCollection DataLst { get { return _dataLst; } set { _dataLst = value; } }

    public UserPreferences()
    {
        Load();
    }

    public void Load()
    {
        if (File.Exists(_dataLstFileName))
        {
            using (var reader = new StreamReader(_dataLstFileName))
            {
                var xs = new XmlSerializer(typeof(DataCollection));
                _dataLst = (DataCollection) xs.Deserialize(reader);
            }
        }
        else
        {
            _dataLst = new DataCollection();
        }
    }

    public void Save()
    {
        using (var writer = new StreamWriter(_dataLstFileName))
        {
            var xs = new XmlSerializer(typeof(DataCollection));
            xs.Serialize(writer, _dataLst);
        }
    }
}

And here is how I call it from my app:

public partial class MainWindow : Window
{
    private DataCollection DataLst;

    ...

    private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        var userPrefs = new UserPreferences();

        userPrefs.DataLst = DataLst; // DataList isn't null and contains correct data
        userPrefs.Save(); 
    }
}

But it creates empty file and hangs up (even without exceptions, just app window becomes black and doesn't response) in the line

var xs = new XmlSerializer(typeof(DataCollection));  

After a little research it seems that there are problems when serializing ObservableCollection<T> . See this blog post for more information.

In summary:

The problem is that the events have not been marked as non-serialized. Therefore, whenever you try to serialize an instance of ObservableCollection, you will also be attempting to serialize any event handlers. When you're using the collection for its primary scenario (data binding), you will have WPF controls attached to the events.

(Kent Boogaart)

Your Data class will also suffer from similar problems; update your PropertyChanged event like so:

[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;

As well as the updates already mentioned by other people, your Data class should also be marked as Serializable .

  1. Your Data class must have a parameter less constructor, otherwise XmlSerializer will never be able to create instance of Data.
  2. Instead of storing DataCoollection, you should store and retrieve Data[], it's easier without having to do anything else.
  3. While storing, you can call ToArray method to get Data[] and use typeof(Data[]) for serializer.
  4. While reading you can read the array and add items into your collection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM