我面临一个无法将序列化对象(使用NewtonsoftJson)重新加载到级联组合框中的问题。我也在使用Prism MVVM lib。
刚启动时我的应用程序按预期运行:
所以我能够根据第一个组合框从第二个组合框中选择值,但是当我保存模型并重新加载模型时,我遇到两个主要问题:
我在这里做错了什么?另外,我不喜欢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>
[序列化期间,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