我在我的应用程序中使用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中更新关系数据绑定有一些特别之处。
有人可以建议解决这个问题吗?
答案 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确定要显示的内容。