2

我使用带有WPF的EF4。我将数据绑定到Master-Detail样式的DataGrid。想想Northwind客户 - >订单 - > OrderDetails。使用EF POCO对象获取只读数据绑定

我在找的是当我使用POCO对象时,Orders和OrderDetails网格是只读的。如果我恢复使用设计器生成的实体,它们将变得可编辑。

结合XAML看起来是这样的:

<Window.Resources> 
    <CollectionViewSource x:Key="CustomersViewSource" d:DesignSource="{d:DesignInstance my:Customer, CreateList=True}" /> 
    <CollectionViewSource x:Key="CustomersOrdersViewSource" Source="{Binding Path=Orders, Source={StaticResource CustomersViewSource}}" /> 
</Window.Resources> 
<Grid DataContext="{StaticResource CustomersViewSource}"> 

    <DataGrid ItemsSource="{Binding}" > 
    <DataGrid ItemsSource="{Binding Source={StaticResource CustomersOrdersViewSource}}" > 

(我已删除属性不相关的数据绑定,当然)。

然后有上下文实例绑定标准形式加载事件:

Dim NorthwindEntities As BindTest.NorthwindEntities = New BindTest.NorthwindEntities() 
Dim CustomersViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("CustomersViewSource"), System.Windows.Data.CollectionViewSource) 
CustomersViewSource.Source = NorthwindEntities.Customers 

的网格填充,但第二个是只读的,如果我用我的POCO对象,如果编辑他们是标准的EF生成的对象。

关键似乎是在实体的导航属性。我POCO对象使用:

Public Overridable Property Orders() As ICollection(Of Order) 
    Get 
     If _Orders Is Nothing Then _Orders = New HashSet(Of Order) 
    Return _Orders 
    End Get 
    Set(ByVal value As ICollection(Of Order)) 
     _Orders = value 
    End Set 
End Property 

尽管EF对象要复杂得多:

<XmlIgnoreAttribute()> 
<SoapIgnoreAttribute()> 
<DataMemberAttribute()> 
<EdmRelationshipNavigationPropertyAttribute("NorthwindModel", "FK_Order_Details_Orders", "Orders")> 
Public Property Order() As Order 
    Get 
     Return CType(Me, IEntityWithRelationships).RelationshipManager.GetRelatedReference(Of Order)("NorthwindModel.FK_Order_Details_Orders", "Orders").Value 
    End Get 
    Set 
     CType(Me, IEntityWithRelationships).RelationshipManager.GetRelatedReference(Of Order)("NorthwindModel.FK_Order_Details_Orders", "Orders").Value = value 
    End Set 
End Property 

对于缺少一些更好的措辞,似乎是无论是对EntityCollection类型的属性一些神奇。 ICollection不是只读接口,HashSet也不是只读接口。

任何有关如何让POCO在这里工作的想法,还是我坚持使用EF派生的对象? (使单元测试变得困难。)

谢谢。

+0

“ICollection ”的具体实例可以只读。它取决于你正在实例化集合的类型。例如'ReadOnlyCollection '是只读的ICollection。由于POCO'Orders'属性的setter是公开的,因此您可以拥有一个只读Orders集合,具体取决于您分配给该属性的集合。你如何填充Customer对象的Orders集合?通过延迟加载? – Slauma 2011-03-22 17:51:35

+0

@Slauma:目前这是懒加载。然而,我的第一个POCO模板只具有导航功能。该属性必须使用内部创建的HashSet,它应该是可编辑的。对于我来说,允许一个外部对象替代一个新的集合引用,对于一个由内部管理的集合引用是没有意义的。因此,最初的POCO类具有只读导航属性。 HashSet是可编辑的,但对其的引用无法更改。为了解决这个问题,我将导航属性改为了读写。 – user458314 2011-03-22 18:17:00

回答

4

问题很可能是您的POCO示例中的OrdersOrderDetails集合的类型为ICollection<T>/HashSet<T>。 WPF数据网格内部不直接与集合一起工作,而是与关联的“集合视图”一起工作。将集合绑定到DataGrid时,WPF绑定引擎将根据集合的类型创建此内部集合视图。

如果您收藏仅仅实现IEnumerable或仅ICollection创建集合视图的类型是CollectionView,一类不实现IEditableCollectionView。这就是为什么当你将HashSet绑定到它时不能编辑DataGrid的原因。

DataGrid需要一个集合视图,它实现了IEditableCollectionView以允许编辑。这是例如ListCollectionView(其也衍生自CollectionView)。如果您的源代码集合实现了IList接口,WPF将创建此类集合视图。

所以,要解决你应该改变你的POCO的Orders属性的类型IList问题:

Public Overridable Property Orders() As IList(Of Order) 
    Get 
     If _Orders Is Nothing Then _Orders = New List(Of Order) 
     Return _Orders 
    End Get 
    Set(ByVal value As IList(Of Order)) 
     _Orders = value 
    End Set 
End Property 

编辑

根据@Allon Guralnek的评论下面,有必要实现非通用IList接口以获得可编辑的数据网格。 List(Of T)就是这种情况,所以上面的代码仍然可以工作。其他只实现了通用IList(Of T)但不是非通用IList的实现不会使DataGrid可编辑。

+0

解决了这个问题。我已经改变了我的T4模板来使用IList,现在一切都很好。详细解释奖金积分(如果我可以给予奖励积分!)。说实话,我对EF和WPF有点不安,因为它们隐藏了很多复杂性,很难找到问题的根源。谢谢! – user458314 2011-03-22 21:16:31

+0

@ user458314:您需要7个以上的声望点(最少15个)才能“提供奖励积分”(aka“vote up”);)我同意通常很难发现问题的来源,特别是在WPF中。我只能回答你的问题,因为我突然想起在一个月前我有同样的问题。当我双击DataGrid并且异常告诉了我一些关于“EditItem不可能用这个视图”或类似的东西时,出现了一个异常。这是一个启动搜索的小提示。我花了一些时间才找到最终的原因。 – Slauma 2011-03-22 21:30:43

+1

只是想澄清一下,为了使DataGrid能够编辑,您必须将其绑定到实现__non-generic__“IList”接口的集合(如果您只实现通用的IList T)',那么它将不可编辑)。 'List '/'List(Of T)'类恰好实现了两者。 – 2011-08-17 06:43:35