Getting Readonly Databind using EF POCO Objects
I am using EF4 with WPF. I am databinding to the DataGrid in a Master-Detail style. Think of the Northwind Customers -> Orders -> OrderDetails.
What I am finding is that when I use POCO objects, the Orders and OrderDetails grids are read-only. If I revert to using the designer generated entities they become editable.
The binding XAML looks like this:
<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}}" >
(I've removed attributes not relevant to databinding, of course.)
Then there's the standard form load event to bind the context instance:
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
The grids populate, but the second is readonly if I'm using my POCO objects, editable if they are the standard EF generated objects.
The key seems to be in the navigation properties of the entities. My POCO objects use:
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
Whereas the EF objects are much more complicated:
<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
For the lack of some better wording, there seems to be some magic in either the attributes for the EntityCollection type. ICollection isn't a readonly interface and a HashSet isn't readonly either.
Any ideas about how to get POCO to work here or am I stuck with EF derived objects? (Makes unit testing difficult.)
T开发者_如何学Chanks.
The problem is likely that the Orders
and OrderDetails
collections are of type ICollection<T>
/ HashSet<T>
in your POCO example. The WPF datagrid internally does not work with the collection directly but rather with an associated "collection view". When you bind the collection to the DataGrid the WPF binding engine creates this internal collection view based on the type of the collection.
If your collection implements only IEnumerable
or only ICollection
the type of the created collection view is CollectionView
, a class which does not implement IEditableCollectionView
. That's the reason why you can't edit the DataGrid when you bind a HashSet to it.
The DataGrid needs a collection view which implements IEditableCollectionView
to allow editing. This is for example the ListCollectionView
(which also derives from CollectionView
). WPF creates this type of collection view if your source collection implements the IList
interface.
So, to fix the problem you should change the type of the Orders
property of your POCO to 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
Edit
According to @Allon Guralnek's comment below it is necessary to implement the non-generic IList
interface to get an editable DataGrid. This is the case for List(Of T)
, therefore the code above will still work. Other implementations which only implement the generic IList(Of T)
but not the non-generic IList
won't make the DataGrid editable.
精彩评论