如何从反序列化的json重新填充视图模型?

时间:2017-09-19 19:01:03

标签: c# wpf mvvm

我的ViewModel类是在我的App.xaml.cs中静态定义的,所以我可以在整个应用程序中访问它。

public static ViewModel.MainViewModel viewModel = new ViewModel.MainViewModel();

使用NewtonSoft JSON.Net库我将我的View模型(忽略我不想保存的某些属性)序列化为JSON字符串,以便像这样保存到文件:

var viewModelJSON = Newtonsoft.Json.JsonConvert.SerializeObject(App.viewModel,Newtonsoft.Json.Formatting.Indented);

要加载它,我打开文本文件并反序列化它:

var viewModel = (ViewModel.MainViewModel)Newtonsoft.Json.JsonConvert.DeserializeObject(contents, typeof(ViewModel.MainViewModel));

反序列化后,我尝试用viewModel替换App.viewModel对象,如下所示:

App.viewModel = viewModel;

...但是所有的绑定都消失了,所以我猜你不能这样做。

所以到目前为止,我唯一的解决办法是遍历每个属性并逐个设置它们,保存的值如下:

            using (StreamReader sr = new StreamReader(openFileDialog.FileName))
            {
                string contents = sr.ReadToEnd();

                var viewModel = (ViewModel.MainViewModel)Newtonsoft.Json.JsonConvert.DeserializeObject(contents, typeof(ViewModel.MainViewModel));

                App.viewModel.telemetryFile = viewModel.telemetryFile;
                App.viewModel.producedOn = viewModel.producedOn;
                App.viewModel.analysisDate = viewModel.analysisDate;
                App.viewModel.systemID = viewModel.systemID;
                App.viewModel.from = viewModel.from;
                App.viewModel.through = viewModel.through;
                //etc
                //etc
            }

但是我要设置很多属性(这里没有列出所有属性)所以写下所有这些行以重新填充Viewmodel似乎效率低下。

有更有效的方法吗? (对于程序员来说很有效,因为逐行编写每一行来重新填充每个属性以用于具有数百个的视图模型可能非常耗时并且容易出错)

修改

根据评论中的建议,我尝试了以下内容 - 向viewmodel添加了属性:

    private MainViewModel _otherViewModel;
    [JsonIgnore]
    public MainViewModel otherViewModel
    {
        get { return _otherViewModel; }
        set
        {
            SetProperty(ref _otherViewModel, value);
        }
    }

在我的视图中,我将数据上下文设置为该属性:

    public TelemetryReport()
    {
        InitializeComponent();
        DataContext = App.viewModel.otherViewModel;
    }

(在XAML中保留所有绑定相同,内部属性从未更改) 例如

<TextBlock Text="{Binding Path=telemetryFile, Mode=OneWay}" />

然后在我打开文件的其他课程中,我这样做了:

            using (StreamReader sr = new StreamReader(openFileDialog.FileName))
            {
                string contents = sr.ReadToEnd();

                var viewModel = (ViewModel.MainViewModel)Newtonsoft.Json.JsonConvert.DeserializeObject(contents, typeof(ViewModel.MainViewModel));

                App.viewModel.otherViewModel = viewModel;

            }

但视图上没有更新任何内容。它应该是吗?

1 个答案:

答案 0 :(得分:2)

这可以通过反思完成,但有更好的方法。我建议您将序列化属性拆分为子视图模型,并为singleton主视图模型提供该类型的属性:

private ChildViewModel _childVM;
public ChildViewModel ChildVM {
    //  standard INotifyPropertyChanged property implementation
}

您的单例主视图模型仍将是所有相同视图的DataContext。但是当您反序列化ChildVM的新副本时,不要复制所有这些属性来引发所有这些PropertyChanged事件,只需将新的反序列化的ChildViewModel实例分配给mainViewModel.ChildVM即可。

在所有观看中,您现在都会这样绑定:

<Label Content="{Binding ChildVM.telemetryFile}" />

以前,telemetryFile是主视图模型的属性,并且绑定看起来像这样:

<Label Content="{Binding telemetryFile}" />