情况:
我有一个绑定到“设置”视图的ViewModel,应该让用户输入许多个性化设置,并且应该能够将它们保存为预设并加载它们。为此,ViewModel包含预设数据模型的集合,这些数据模型本身具有不同的属性,类对象等。 该计划是通过对整个ViewModels进行xml序列化和反序列化来实现保存所有预设的。
代码/问题
从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()
,所以反序列化器会在永无止境的循环中调用自己,从而导致stackoverflow错误。
因此,最简单的解决方案应该是使用另一个带有参数的构造函数,我在其中调用InitializePresetsFromFile()
,对吗?这里的问题是ViewModel类是在相应View的xaml中直接实例化的:
<UserControl.Resources>
<ResourceDictionary>
<vm:LinearAxisColorPresetsViewModel x:Key="vm" />
</ResourceDictionary>
</UserControl.Resources>
This posts的第二个答案表明约定是,从XAML调用的构造函数应该是无参数的,我想坚持这一点。
问题:
问题仅是如何根据最佳实践解决此问题。由于这是我对序列化和反序列化的首次尝试,因此我担心自己在这里走错了路。我的感觉是只有数据模型类应该序列化。我的ViewModel拥有两个此类的ObservableCollection,但是我想序列化完整的集合以及ViewModel中的其他属性(例如,选定的索引)。
答案 0 :(得分:2)
您确实已经达到必须决定如何继续的地步。您现在正在做什么将无法工作。在这种情况下,XML序列化程序和XAML都使用默认构造函数。您不能在这里将其用于两个目的。
我的建议是创建一个类,该类反映用于反序列化XML文件的视图模型中的属性。此类仅需要属性,仅此而已。
如果视图模型类实际上是静态的,则可以使用a locator class将其绑定到。
答案 1 :(得分:0)
首先,您不应在类的构造函数中调用InitializePresetsFromFile
方法。构造函数必须尽可能快,并且不会引起副作用。在构造函数中读取文件是一个坏习惯:如果不访问文件系统,就无法创建类的实例。这意味着您的代码不可测试,容易出错(例如,您是否想到突然的UnauthorizedAccessException
?),而且速度很慢。
相反,创建一个公共方法以反序列化文件中的数据。这将破坏您无休止的递归。
如何调用该方法?
LinearAxisColorPresetsViewModel
实例吗?如果没有,只需将反序列化的实例分配给视图的DataContext
属性。ICommand
,例如InitializeCommand
使用上述方法从文件初始化内部状态;在应用启动/查看显示等时执行该命令。您可以使用例如InvokeCommandAction
代表Loaded
事件。