在WPF中反序列化后无法加载组合框项目源

问题描述 投票:2回答:1

我面临一个无法将序列化对象(使用NewtonsoftJson)重新加载到级联组合框中的问题。我也在使用Prism MVVM lib。

刚启动时我的应用程序按预期运行:

enter image description here

所以我能够根据第一个组合框从第二个组合框中选择值,但是当我保存模型并重新加载模型时,我遇到两个主要问题:

  • SelectedItem属性从不设置(即使调试器也表明它不为空)
  • 即使似乎已加载值,第二个组合框仍为空,看起来像:

enter image description here

我在这里做错了什么?另外,我不喜欢ComboboxSelectionChanged方法,因此也许有人可以指出我基于MVVM的方法。

这是最小的工作示例:

MainWindow.xaml.cs

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    private ViewModel viewModel;

    public MainWindow()
    {
        InitializeComponent();

        viewModel = new ViewModel();

        ConstructRandomData();

        DataContext = viewModel;
    }

    private void ConstructRandomData()
    {
        // Construct data
        for (int i = 0; i < 5; i++)
        {
            var ids = new List<SubId>();

            for (int r = 0; r < 10; r++)
            {
                ids.Add(
                    new SubId
                    {
                        Name = $"Id_{i}.{r}"
                    }
                );
            }

            viewModel.MainIds.Add(
                new MainId
                {
                    Name = $"MainId{i}",
                    SubIds = ids
                });
        }
    }

    private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        ComboBox combo = sender as ComboBox;

        if (combo.SelectedItem is MainId selectedItem)
        {
            var subIdList = (from mainId in viewModel.MainIds
                                  where mainId.Name.Equals(selectedItem.Name)
                                  select mainId.SubIds).First();

            viewModel.SubIds.Clear();

            viewModel.SubIds.AddRange(subIdList.ToArray());

        }

    }

    private void SaveButtton_Click(object sender, RoutedEventArgs e)
    {
        File.WriteAllText("savedData.json", JsonConvert.SerializeObject(viewModel));
    }

    private void LoadButton_Click(object sender, RoutedEventArgs e)
    {
        ViewModel deserializedModel = JsonConvert.DeserializeObject<ViewModel>(File.ReadAllText("savedData.json"));

        viewModel.MainIds = deserializedModel.MainIds;
        viewModel.SubIds = deserializedModel.SubIds;
    }
}

public class ViewModel : BindableBase
{
    public ObservableCollection<MainId> MainIds { get; set; } = new ObservableCollection<MainId>();
    public ObservableCollection<SubId> SubIds { get; set; } = new ObservableCollection<SubId>();

    private MainId mainId;
    public MainId SelectedMainId
    {
        get { return mainId; }
        set { SetProperty(ref mainId, value); }
    }

    private SubId selectedId;
    public SubId SelectedId
    {
        get { return selectedId; }
        set { SetProperty(ref selectedId, value); }
    }
}
public class MainId : BindableBase
{
    private string name;
    public string Name
    {
        get { return name; }
        set 
        { 
            SetProperty(ref name, value); 
        }
    }

    public List<SubId> SubIds { get; set; } = new List<SubId>();
}
public class SubId : BindableBase  
{
    private string name;
    public string Name
    {
        get { return name; }
        set { SetProperty(ref name, value); }
    }
}

The MainWindow.xaml

<Window x:Class="CascadingComboBox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:CascadingComboBox"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel Margin="30">
        <ComboBox Margin="5" Width="150" 
                  ItemsSource="{Binding MainIds}" 
                  DisplayMemberPath="Name" 
                  SelectedItem="{Binding SelectedMainId}"
                  SelectionChanged="ComboBox_SelectionChanged"/>
        <ComboBox Margin="5" Width="150" 
                  ItemsSource="{Binding SubIds}" 
                  SelectedItem="{Binding SelectedId}"
                  DisplayMemberPath="Name"/>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="10">
            <Button Margin="5" Width="50" Content="Save" Click="SaveButtton_Click" />
            <Button Margin="5" Width="50" Content="Load" Click="LoadButton_Click"/>
        </StackPanel>
    </StackPanel>
</Window>
c# wpf combobox
1个回答
0
投票

[序列化期间,SelectedItem包含来自ComboBoxItems集合的对象。

但是在反序列化之后,这不再成立:SelectedItem现在是一个新实例,即使它的内容与ComboBoxItems中的一项相同。默认情况下,这就是Json.NET的工作方式。

您可以通过更改PreserveReferencesHandling选项来解决此问题:

var jsonSettings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects };

JsonConvert.SerializeObject(model, Formatting.Indented, jsonSettings);

...

model = JsonConvert.DeserializeObject<List<Person>>(json, jsonSettings);

https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_PreserveReferencesHandling.htm

© www.soinside.com 2019 - 2024. All rights reserved.