EF EntityObject不更新关系的数据绑定

时间:2011-07-15 12:52:52

标签: wpf mvvm entity-framework-4 entityobject

我在我的应用程序中使用EntityFramework,WPF和MVVM,并且在更新EntityObjects之间关系的数据绑定方面遇到了一些问题。我能够将我的问题缩小到只有几行XAML,我希望有人可以帮助我,因为我对EF和MVVM仍然不太自信。

无论如何,我们在这里使用简化的XAML:

    <DatePicker Grid.Row="2" Grid.Column="1" 
                    SelectedDate="{Binding Path=File.SentDate, 
StringFormat={}{0:dd/MM/yyyy}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                    VerticalAlignment="Center" IsEnabled="{Binding Path=IsEnabled}"/>

        <ComboBox Grid.Row="3" Grid.Column="1" ItemsSource="{Binding Contacts}" DisplayMemberPath="Name" 
                  SelectedItem="{Binding Path=File.Sender, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEditable="True"
                  VerticalAlignment="Center">
        </ComboBox>

        <Label Content="{Binding Path=File.SenderId}" Grid.Row="4"/>
        <Label Content="{Binding Path=File.Sender.Name}" Grid.Row="5"/>
        <Label Content="{Binding Path=File.SentDate}" Grid.Row="6"/>

我正在使用最后3个标签来测试我的数据绑定。使用DatePicker更改File.SentDate会将数据绑定更新到最后一个Label而不会出现问题。

现在File的类型为EntityObject,并且具有GUID类型的SenderId属性。它还通过Sender属性与我的Contacts有关系。显然,SenderId是相应的Contact EntityObject的GUID,它通过Sender关系与File相关。一个文件只能有一个类型为Contact的单个Sender。

无论如何,当我使用组合框选择另一个发件人时,显示File.SenderId属性的Label会被正确更新。但是,具有File.Sender.Name属性的属性(即使用reléationship的属性)不会更新。

所以我猜测在EF中更新关系数据绑定有一些特别之处。

有人可以建议解决这个问题吗?

3 个答案:

答案 0 :(得分:1)

不幸的是,当关联属性发生更改时,实体框架不会通知。这就是你的Binding无效的原因。

向Microsoft报告此问题:http://connect.microsoft.com/VisualStudio/feedback/details/532257/entity-framework-navigation-properties-don-t-raise-the-propertychanged-event

WPF Application Framework (WAF) BookLibrary 示例应用程序显示了另一种解决方法。 Book类侦听AssociationChanged事件并引发相应的PropertyChanged事件。

public Book()
{
    …
    LendToReference.AssociationChanged += LendToReferenceAssociationChanged;
}

private void LendToReferenceAssociationChanged(object sender, 
        CollectionChangeEventArgs e)
{
    // The navigation property LendTo doesn't support the PropertyChanged event. 
    // We have to raise it ourselves.
    OnPropertyChanged("LendTo");
}

答案 1 :(得分:0)

看起来我找到了一个解决方案,虽然对我来说它更像是一种解决方法。这不是我的解决方案 会有所期待,但它的确有效。

除了一件事,XAML仍然与上面相同。我没有绑定到File.Sender.Name,而是像这样绑定到File.SenderName:

<Label Content="{Binding Path=File.SenderName}" Grid.Row="4"/>

在这种情况下,SenderName是对象File的一个属性,我在这样的部分类中添加了这个:

public partial class File
{
        public string SenderName
        {
            get
            {
                if (this.Sender != null)
                {
                    return this.Sender.Name;
                }

                return string.Empty;
            }
        }
protected override void OnPropertyChanged(string property)
        {

            if (property == "SenderId")
            {
                OnPropertyChanged("SenderName");
            }
            base.OnPropertyChanged(property);
        }
}

所以这里发生的是如果SenderId属性被更改,我告诉框架也更新SenderName属性。而已。奇迹般有效。虽然我仍然不相信这是它的工作方式。

答案 2 :(得分:0)

如果您只想要一个名称,另一种解决方法是覆盖发件人的ToString()并直接绑定到发件人。这种解决方法很好,因为大多数情况下,当我们对属性的属性进行数据绑定时,我们这样做是为了将对象的“名称”设置为属性值。此外,如果您编辑tt文件以将部分添加到所有类定义,此方法也适用于Database First方法。

因此,您添加一个文件以包含您的Entites的ToString扩展名,并在其中添加如下内容:

public partial Contacts 
{
    public override string ToString()
    {
        return Name;
    }
}

所以你可以数据绑定

<Label Content="{Binding Path=File.Sender}" Grid.Row="5"/>

现在数据绑定将检测发件人是否发生变化,当发生变化时,它将调用ToString来确定要显示的内容。

另一方面,如果您需要绑定到另一个非标准属性,则可能会遇到问题。我确实记得成功使用DataContext和模板来解决它。绑定到Sender并使用DataTemplate确定要显示的内容。