我在数据绑定和实体框架的导航属性方面遇到了一些问题。
我有两个类,由实体框架设计器生成:
福类:
id (int)
bar (Bar)
...
类栏
id (int)
name (string)
...
使用ObservableCollection<Foo>
,我用以下列填充了一个数据网格:
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding Path=id}"/>
<DataGridTemplateColumn Header="Bar">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
SelectedValuePath="Id"
SelectedValue=
"{Binding Path=bar.Id, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="name"
ItemsSource=
"{Binding Path=BarList,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}}"
Background="White" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
组合框填充了一个ObservableCollection<Bar>
,并正确显示当前Bar
。
当我在组合框中选择另一个项目时,问题就来了。我收到以下错误:
System.Windows.Data Error: 8 : Cannot save value from target back to source.
System.InvalidOperationException: The property 'Id' is part of the object's key information and cannot be modified
我可以看到为什么会弹出错误,但是我该如何以不同的方式处理这个问题?
编辑:Foo
和Bar
之间的关系是N。1,表示一个Foo
有 1 或 0 Bar
,而一个柱可以有几个Foo
。
目前,我无法为我的Foo
选择新Bar
。
您必须直接绑定bar
属性。您的代码尝试更改所选 Foo 的栏上的Id
,但您想要的是更改与当前 Foo 关联的栏。您还必须重写Bar
类上的Equals
方法。
<ComboBox SelectedValue="{Binding bar, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Name"
ItemsSource="{Binding Path=BarList, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Background="White" />
在你的Bar
课上:
public override bool Equals(object obj)
{
if (obj is Bar)
return ((Bar)obj).Id == Id;
return false;
}
如果您不想直接使用对象来执行此操作(这意味着不使用SelectedValuePath
和SelectedValue
而是直接使用SelectedItem="{Binding Foo.Bar}"
,则需要指示 EF 设计器generate foreign key property BarId on the Foo entity
,然后您可以绑定SelectedValue="{Binding Foo.BarId}"
。
对我来说,问题似乎更多地在于实体框架而不是WPF。bar的id同时是foo主键的一部分是正确的吗?至少绑定,组合框的设置和错误消息似乎暗示了这一点。
实体框架的限制之一是它不支持密钥更新。如果要更改对象的键,基本上必须删除它,使用新键重新创建它,然后复制所有其他属性。在我目前正在处理的一个程序中,我决定创建一个包装类,它将 Id 公开为属性,并在更改时在幕后执行此处理。我见过建议仅分离对象并重用它的帖子,但就我而言,这不起作用。