简体   繁体   English

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

[英]EF EntityObject not updating databindings of relationships

I'm using EntityFramework, WPF and MVVM in my application and got some problems with updating the databinding of relationships between EntityObjects.我在我的应用程序中使用 EntityFramework、WPF 和 MVVM,但在更新 EntityObjects 之间关系的数据绑定时遇到了一些问题。 I was able to downsize my problem to only a few lines of XAML and I hope someone can help me as I'm still not very confident with EF and MVVM.我能够将我的问题缩小到只有几行 XAML 并且我希望有人可以帮助我,因为我对 EF 和 MVVM 仍然不是很有信心。

Anyway, here we go with the simplified XAML:无论如何,这里我们 go 和简化的 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"/>

I'm using the last 3 Labels to test my databinding.我正在使用最后 3 个标签来测试我的数据绑定。 Changing the File.SentDate using the DatePicker updates the databinding to the last Label without problem.使用 DatePicker 更改 File.SentDate 将数据绑定更新到最后的 Label 没有问题。

Now File is of type EntityObject and has a SenderId property of type GUID.现在 File 是 EntityObject 类型,并且具有 GUID 类型的 SenderId 属性。 It also has a relationship to my Contacts through the Sender property.它还通过 Sender 属性与我的联系人有关系。 Obvisouly, SenderId is the GUID of the corresponding Contact EntityObject which is related to File through the Sender relationship.显然,SenderId 是通过 Sender 关系与 File 相关的对应 Contact EntityObject 的 GUID。 A File can have only 1 single Sender of type Contact.一个文件只能有 1 个联系人类型的发件人。

Anyway, what happens is that when I select another sender using the combobox, the Label displaying the File.SenderId property get properly updated.无论如何,发生的情况是,当我 select 另一个发件人使用 combobox 时,显示 File.SenderId 属性的 Label 得到正确更新。 However, the one with the File.Sender.Name property ie the one using the reléationship does not get updated.但是,具有 File.Sender.Name 属性的那个,即使用关系的那个没有得到更新。

So I'm guessing that there is something special about updating the databinding of relationships in EF.所以我猜想在 EF 中更新关系的数据绑定有一些特别之处。

Can someone please suggest a solution to this?有人可以提出解决方案吗?

Unfortunately, the Entity Framework doesn't notify when an association property changes.不幸的是,实体框架不会在关联属性更改时发出通知。 That's the reason why your Binding didn't work.这就是您的绑定不起作用的原因。

The issue is reported to Microsoft: http://connect.microsoft.com/VisualStudio/feedback/details/532257/entity-framework-navigation-properties-don-t-raise-the-propertychanged-event该问题已报告给 Microsoft: http://connect.microsoft.com/VisualStudio/feedback/details/532257/entity-framework-navigation-properties-don-t-raise-the-propertychanged-event

Another workaround is shown by the BookLibrary sample application of the WPF Application Framework (WAF) . WPF 应用程序框架 (WAF)BookLibrary示例应用程序显示了另一种解决方法。 The Book class listens to the AssociationChanged event and raises the appropriate PropertyChanged event. Book class 监听 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");
}

Another workaround if you simply want a name is to overide ToString() for the Sender and bind directly to sender.如果您只是想要一个名称,另一种解决方法是覆盖 Sender 的 ToString() 并直接绑定到发件人。 This workaround is good because most of the time when we are databinding to Property of a Property we do it in order to get a "name" of object set as property value.这种解决方法很好,因为大多数时候我们将数据绑定到属性的属性时,我们这样做是为了将 object 的“名称”设置为属性值。 Also this method works for Database First approach too if you edit tt files to add partial to all class definitions.如果您编辑 tt 文件以将部分添加到所有 class 定义,则此方法也适用于数据库优先方法。

So you add a file to contain ToString extensions of your Entites and in it you add something like this:因此,您添加一个文件以包含您的实体的 ToString 扩展名,并在其中添加如下内容:

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

so you can databind所以你可以数据绑定

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

Now the databinding will detect if the Sender changes, and when it does it will call ToString to determine what to display.现在数据绑定将检测 Sender 是否更改,当它发生更改时,它将调用 ToString 以确定要显示的内容。

On the other hand if you need to bind to another non standard property you might have problems.另一方面,如果您需要绑定到另一个非标准属性,您可能会遇到问题。 I do remember having success with using DataContext and templates to get around it.我确实记得成功使用 DataContext 和模板来解决它。 You bind to Sender and use DataTemplate to determine what to display.您绑定到 Sender 并使用 DataTemplate 来确定要显示的内容。

Looks like I've found a solution, though to me its more like a workaround.看起来我已经找到了解决方案,尽管对我来说它更像是一种解决方法。 It's not the solution I would have expected but it works.这不是我所期望的解决方案,但它有效。

The XAML is still the same as above, except for one thing. XAML 还是和上面一样,除了一件事。 Instead of binding to File.Sender.Name, I bind to File.SenderName like this:我没有绑定到 File.Sender.Name,而是像这样绑定到 File.SenderName:

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

SenderName in this case is a property of the object File which I added in a partial class like this:在这种情况下,SenderName 是 object 文件的属性,我在部分 class 中添加了该文件,如下所示:

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);
        }
}

So what happens here is that if the SenderId property is changed, I tell the framework to also update the SenderName property.所以这里发生的情况是,如果 SenderId 属性发生更改,我会告诉框架也更新 SenderName 属性。 That's it.而已。 Works like a charm.奇迹般有效。 Although I'm still not convinced that this is the way it is supposed to work.尽管我仍然不相信这是它应该工作的方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM