Search code examples
c#.netserializationxml-serialization

Is it not possible to deserialize to 'this' from default constructor?


The Situation:

I have a ViewModel bound to a Settings View, where the user is supposed to enter a lot of personalized settings and should be able to save them as presets and load them. For this the ViewModel holds Collections of preset data models which themselves hold different properties, class objects and so on. The plan is to achieve saving all the presets by xml serialization and deserialization of the whole ViewModels.

The Code / The Problem

From the Constructor of the ViewModel I call the following method:

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

So the Method checks if the file holding the preset exists - if it doesn't it should setup an empty preset and save it to a newly created file, otherwise it should load the preset from the existing file.

The serialization process works fine, however since I serialize to this there is a problem with deserializiation:

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;
}

The problem here is, that since I'm calling the method InitializePresetsFromFile() directly from the constructor, the deserializer calls himself in an never ending loop resulting in an stackoverflow error.

So, the most simple solution should be to use another constructor with a parameter, where I call InitializePresetsFromFile(), right? The problem here is that the ViewModel class is directly instantiated within the xaml of the corresponding View:

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

This posts second answer states that convention is, that constructors called from XAML should be parameterless and I want to stick to that.

The question:

The question is simply how to go about this problem according to best practice. Since this is my first attempt on serialization and deserialization I fear, that I'm a bit on the wrong path here. My feeling is that only data model classes should be serialized. My ViewModel holds two ObservableCollection of such classes, however I want to serialize the complete collections as well as other properties within the ViewModel such as the selected index.


Solution

  • You have indeed reached a point where you have to decide how to continue. What you are doing now is not going to work. Both the XML serializer and XAML uses the default constructor in this case. You can't make it serve two purposes here.

    My advice would be to create a class that mirrors the properties from your view model which you use to deserialize the XML file. This class only needs the properties, nothing more.

    If the view model class is actually a static, you could use a locator class to bind it to.