Partager via


WPF databinding with the POCO Template

Update: with the new version of the POCO template available in Visual Studio Gallery (see here for more information), there is no need for this workaround. We decided to change the collection type for navigation properties to be based on ObservableCollection<T>, so that an IListSource implementation shouldn’t be required anymore.

The new support for POCO in Entity Framework seeks to enable better ways of coding application domain logic without polluting domain classes with persistence concerns. Persistence Ignorance can in fact improve maintainability, testability and evolvability of an application by making it possible to write domain classes that the contain domain logic and nothing more.

Persistence isn’t however the only common infrastructure service that might affect how you write your classes. Others, such as databinding and serialization, sometimes require more than POCO types to work really well.

Disclaimer: I am not trying to enter a debate on whether you should use domain entities directly in databinding and serialization, I am aware of the recommended patterns :)

For instance, to get databinding to fully work with a domain model, each object and collection type has to implement a number of interfaces for things like change notification, type description, capability negotiation, etc. That said, a decent level of databinding support can be achived with simple POCO types and collection types that implement IList, such as List<T>.

In the POCO Template that is included in the Entity Framework Feature CTP 1, we use T4 code generation to produce POCO entity classes and a “typed” ObjectContext class based on an Entity Data Model. The POCO Template emits a special collection type named FixupCollection that has the capability to synchronize changes on both sides of a relationship (typically a one-to-many relationship is represented as a collection on the one side, and as a reference in each object of the many side). But as a colleague of mine found today, Since FixupCollection derives from ICollection<T> and not IList<T>, WPF databinding will not work with it in read-write scenarios.

If you try to bind to a collection emitted by the POCO Template (i.e. in a master-detail form), and the you try to edit it, you will run into this exception message:

'EditItem' is not allowed for this view.

The exception indicates that WPF considers that the collection is read-only.

Here is a way to overcome this:

  • Extend FixupCollection in a partial class to implement IListSource.
  • The implementation of IListSource.GetList has to return a binding list. For instance, I implemented a custom ObservableCollection that has the necessary hooks to update the underlying FixupCollection whenever elements are added or removed.
  • Currently, this doesn’t work the other way around. For instance, when entities added or removed in the underlying collection, the ObservableCollection is not updated.

Here is the code:

using System.Collections.ObjectModel;
using System.ComponentModel;
//TODO: update the namespace to match the same as the code-gen
//FixupCollection
namespace Model
{
public partial class FixupCollection<TFrom, TTo> : IListSource
{
bool IListSource.ContainsListCollection
{
get { return false; }
}

System.Collections.IList IListSource.GetList()
{
return new FixupCollectionBindingList<TFrom, TTo>(this);
}
}

public class FixupCollectionBindingList<TFrom, TTo> :
ObservableCollection<TTo>
{
private readonly FixupCollection<TFrom, TTo> _source = null;

public FixupCollectionBindingList(
FixupCollection<TFrom, TTo> source)
: base(source)
{
this._source = source;
}

protected override void InsertItem(int index, TTo item)
{
_source.Add(item);
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
_source.Remove(this[index]);
base.RemoveItem(index);
}
}
}

Hope this helps,

Diego

Comments

  • Anonymous
    August 04, 2009
    Hi Diego interesting point and nice fix. As a WPF newbie, in the midst of my first app., I was under the impression that full two way binding required dependency properties on your entities. Obviously with POCO objects such properties are not evident. Do we still get full binding on POCO objects? Cheers AndyF.

  • Anonymous
    August 05, 2009
    Hello Andy, While things like DependencyProperties and the "INotify" interfaces are important to get full functionality, databinding can "degrade gracefully" in absence of them. For instance, with typical POCO classes, the UI won’t refresh automatically if changes are made to the underlying property through some other mechanism (i.e. setting the property value directly in code), however this behavior can be ok if only databinding is the source of changes. For collections that are not ILists the degradation is unfortunately more abrupt.  

  • Anonymous
    February 23, 2010
    Now in RC, it's not need to do this, is it?

  • Anonymous
    February 23, 2010
    @tubo, Good catch! In the POCO template for RC that is now available in Visual Studio Gallery (see more information here: http://blogs.msdn.com/adonet/archive/2010/02/18/entity-framework-poco-template-updated-for-visual-studio-2010-release-candidate.aspx), we decided to use a collection type based on ObservableCollection for the collection navigation properties, so this shouldn't be necessary anymore. Thanks, Diego