#c_sharp #wpf
Есть такой класс: public class ChapterCollection : ObservableCollection{ public bool? IsSelectedAll { get { return _isSelectedAll; } set { _isSelectedAll = value; OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsSelectedAll))); } } } При его сериализации в XML свойство IsSelectedAll не сериализуется. Только коллекция объектов ChapterVM. Как сериализовать свойство? Сериализация происходит так: public static void SerializeToXml(string path, object saveObject) { var formatter = new XmlSerializer(saveObject.GetType()); using (FileStream fs = new FileStream(path, FileMode.Create)) { formatter.Serialize(fs, saveObject); } }
Ответы
Ответ 1
Наиболее простым решением является отказ от наследования в пользу композиции. Действительно, логично предположить что ChapterCollection не просто "является" коллекцией ChapterVM, а содержит в себе коллекцию ChapterVM и также некоторые другие свойства, как признак выделенности элементов коллекции и т.п. Зы. Недаром умные книги по проектированию пишут Предпочитайте композицию наследованию Если всё же вы намерены оставить наследование, для переопределения действий сериализатора необходимо реализовать интерфейс IXmlSerializable. Сделать это можно примерно так: public class ChapterCollection : ObservableCollection, IXmlSerializable { bool? _isSelectedAll; public bool? IsSelectedAll { get { return _isSelectedAll; } set { _isSelectedAll = value; OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsSelectedAll))); } } public XmlSchema GetSchema() => null; public void ReadXml(XmlReader reader) { reader.ReadStartElement(); // Читаем из потока дополнительные свойства вручную IsSelectedAll = reader.ReadElementContentAsBoolean(nameof(IsSelectedAll), ""); // Читаем элементы коллекции XmlSerializer ser = new XmlSerializer(typeof(Chapter)); while (reader.NodeType == XmlNodeType.Element) Add((Chapter)ser.Deserialize(reader)); reader.ReadEndElement(); } public void WriteXml(XmlWriter writer) { // Сериализуем дополнительные свойства вручную writer.WriteStartElement(nameof(IsSelectedAll)); writer.WriteValue(IsSelectedAll); writer.WriteEndElement(); // Сериализуем элементы коллекции XmlSerializer ser = new XmlSerializer(typeof(Chapter)); foreach (var ch in this) ser.Serialize(writer, ch); } } Дополню ответ вариантом сериализации при композиции. Наш класс коллекции превращается в такой: public class ChapterCollection { public bool? IsSelectedAll { get; set; } public ObservableCollection Collection { get; } = new ObservableCollection (); } Обратите внимание, создать экземпляр нужно обязательно вручную, сериализатор не может создавать "кастомные" коллекции, поэтому он не заполнит ее: = new ObservableCollection (); Но зато открывать свойство коллекции на запись (set;) не нужно. Теперь вы можете использовать Linq, но придется указать имя этого свойства-коллекции: myChapterCollection.Collection.Select(...); Если вы реализуете IEnumerable<>, то сериализатор опять начнет думать что это коллекция и потеряет свойства, да еще к тому же потребует реализовать нетипизированный метод Add(object), что уже некрасиво и добавляет некоторую хрупкость. PS: благодаря утиной типизации C# можно все же добавить маленький кусочек сахара, добавив в класс метод: public IEnumerator GetEnumerator() => ((IEnumerable )Collection).GetEnumerator(); это хоть и не даст воспользоваться LINQ на экземпляре класса, но позволит упростить код foreach: // myChapterCollection.Collection писать не требуется: foreach (var chapter in myChapterCollection) ...
Комментариев нет:
Отправить комментарий