Разве невозможно десериализовать это из конструктора по умолчанию? - PullRequest
0 голосов
/ 04 марта 2019

Ситуация:

У меня есть ViewModel, привязанная к представлению настроек, где пользователь должен вводить множество персонализированных настроек и должен иметь возможность сохранять их как предустановки изагрузить их.Для этого ViewModel содержит коллекции предустановленных моделей данных, которые сами содержат различные свойства, объекты классов и так далее.План состоит в том, чтобы добиться сохранения всех предустановок путем сериализации xml и десериализации всей модели ViewModels.

Код / Проблема

Из конструктора ViewModel я вызываю следующий метод:

private void InitializePresetsFromFile()
{
    if (!File.Exists(Info.GetDefaultColorPalettePresetsXml()))
    {
        SetupNewEmpty();
        SerializePresets(Info.GetDefaultColorPalettePresetsXml());
    }
    else
    {
        DeserializePresets(Info.GetDefaultColorPalettePresetsXml());
    }
}

Итак, метод проверяет, является ли методфайл, содержащий пресет, существует - если этого не происходит, он должен установить пустой пресет и сохранить его во вновь созданном файле, в противном случае он должен загрузить пресет из существующего файла.

Процесс сериализации работает нормально, однако, поскольку я сериализуюсь в this, существует проблема с десериализацией:

private void DeserializePresets(string path)
{
    XmlSerializer deserializer = new XmlSerializer(typeof(LinearAxisColorPresetsViewModel));
    TextReader reader = new StreamReader(path);
    object obj = deserializer.Deserialize(reader);
    LinearAxisColorPresetsViewModel XmlData = (LinearAxisColorPresetsViewModel)obj;
    reader.Close();
    VolumePresetList = XmlData.VolumePresetList;
    WaveShapePresetList = XmlData.WaveShapePresetList;
    VolumePresetSelectedIndex = XmlData.VolumePresetSelectedIndex;
    WaveShapePresetSelectedIndex = XmlData.WaveShapePresetSelectedIndex;
}

Проблема в том, что, поскольку я вызываю метод InitializePresetsFromFile() непосредственно из конструктора, десериализатор вызывает себя в бесконечном цикле, что приводит к ошибке переполнения стека.

Итак, самое простое решение - использовать другой конструктор с параметром, где я называю InitializePresetsFromFile(), верно?Проблема здесь в том, что класс ViewModel непосредственно создается в xaml соответствующего View:

<UserControl.Resources>
    <ResourceDictionary>
        <vm:LinearAxisColorPresetsViewModel x:Key="vm" />
    </ResourceDictionary>
</UserControl.Resources>

В этом посте второй ответ гласит, что соглашение состоит в том, что конструкторы, вызываемые из XAML, должны бытьбез параметров, и я хочу придерживаться этого.

Вопрос:

Вопрос заключается в том, как решить эту проблему в соответствии с передовой практикой.Так как это моя первая попытка сериализации и десериализации, я боюсь, что я немного на неверном пути.Мне кажется, что только классы модели данных должны быть сериализованы.Моя ViewModel содержит две ObservableCollection таких классов, однако я хочу сериализовать полные коллекции, а также другие свойства в ViewModel, такие как выбранный индекс.

Ответы [ 2 ]

0 голосов
/ 04 марта 2019

Прежде всего, вы не должны вызывать метод InitializePresetsFromFile в конструкторе класса.Конструктор должен быть максимально быстрым и не должен вызывать побочных эффектов.Чтение файла в конструкторе - плохая практика: вы не можете создать экземпляр своего класса без доступа к файловой системе.Это означает, что ваш код не тестируемый, он подвержен ошибкам (например, вы думали о внезапных UnauthorizedAccessException s?) И работает медленно.

Вместо этого создайте открытый метод, который десериализует данные изфайл.Это нарушит вашу бесконечную рекурсию.

Как вызвать этот метод?

  • Вам действительно нужен экземпляр LinearAxisColorPresetsViewModel в словаре ресурсов?Если нет, просто назначьте десериализованный экземпляр свойству DataContext вашего представления.
  • Если вам это нужно, создайте в вашей модели представления ICommand например InitializeCommand, который использует вышеупомянутый методинициализировать внутреннее состояние из файла;выполнить эту команду при запуске приложения / просмотре шоу и т. д. Вы можете использовать, например, InvokeCommandAction для события Loaded.
0 голосов
/ 04 марта 2019

Вы действительно достигли точки, когда вам нужно решить, как продолжить.То, что вы делаете сейчас, не сработает.В этом случае и XML-сериализатор, и XAML используют конструктор по умолчанию.Вы не можете заставить его служить двум целям.

Мой совет - создать класс, который будет отражать свойства из вашей модели представления, которые вы используете для десериализации файла XML.Этому классу нужны только свойства, не более того.

Если класс модели представления на самом деле является статическим, вы можете использовать класс локатора , чтобы связать его с.

...