【问题标题】:Data binding with Entity Framework Navigation properties using ComboBox使用 ComboBox 与实体框架导航属性进行数据绑定
【发布时间】:2012-11-04 02:19:30
【问题描述】:

我在数据绑定和实体框架的导航属性方面遇到了一些问题。

我有两个类,由实体框架设计器生成:

Foo 类

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>

ComboBox 填充了ObservableCollection&lt;Bar&gt;,并且正确显示了当前的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

我知道为什么会弹出错误,但我该如何以不同的方式处理呢?

编辑:FooBar 之间的关系是 N..1,这意味着一个 Foo 有 1 个或 0 个 Bar,而一个 Bar 可以有多个 Foos。

目前,我无法为我的Foos 选择新的Bar

【问题讨论】:

  • 你好@thakrage!你到底想在这里实现什么?更改其中一个 ViewModel 的 id 确实看起来有问题!
  • 我没有使用 MVVM,但我想要一个包含 Bars 列表的组合框。从这个列表中,我希望能够为我的 Foo 选择另一个 Bar。我将编辑问题
  • 即使您没有使用 MVVM,您的 DataGrid 似乎也已绑定。因此,您的每一行都是从底层对象(在您的情况下为 Foo)生成的,您想在选择 ComboBox 中的值时修改 ObservableCollection 吗?编辑:刚刚看到你的编辑:所以comboxBox是为了允许用户为给定的Foo选择一个Bar?
  • 完全正确。组合框旨在允许用户为每个 Foo 分配一个新 Bar。每当我这样做时,就会发生异常。
  • 我会尽快为您准备好解决方案

标签: wpf data-binding datagrid combobox navigation


【解决方案1】:

您必须直接绑定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;
}

【讨论】:

    【解决方案2】:

    如果您不想直接使用对象(即不使用SelectedValuePathSelectedValue,而是直接使用SelectedItem="{Binding Foo.Bar}",则需要指示EF设计人员使用generate foreign key property BarId on the Foo entity,则可以绑定SelectedValue="{Binding Foo.BarId}"

    【讨论】:

      【解决方案3】:

      在我看来,Entity-Framework 的问题比 WPF 的问题更多。 bar 的 id 同时是 foo 主键的一部分是否正确?至少绑定、ComboBox 的设置和错误消息似乎暗示了这一点。

      实体框架的限制之一是它不支持密钥更新。如果要更改对象的键,则基本上必须删除它,使用新键重新创建它,然后复制所有其他属性。在我目前正在处理的一个程序中,我决定创建一个包装类,它将 Id 作为属性公开,并在它更改时在幕后进行处理。我看过一些帖子建议只分离对象并重用它,但在我的情况下这不起作用。

      【讨论】:

      • 嗯,Entity-Framework 没有问题,问题确实出在 WPF 上。如果您阅读我们的 cmets,thakrage 声明他想要更改与 Foo 关联的栏,他的绑定尝试更改栏的 ID(由于密钥更新限制,这确实看起来不正确)。这是一个简单的绑定错误。
      • 转念一想,我认为你是对的。我可能被错误消息误导了。这完全取决于错误代码的意图。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多