Collection Binding Options in WCF RIA Services SP1

One of the most common tasks when developing a RIA Services application binding to a collection of data. There are some declarative options that include binding directly to your DomainContext or DomainDataSource. These options are great for spinning up applications quickly, but don’t translate well to view model patterns. For that reason, I thought it’d be worth taking a moment to go through the options that make sense in an MVVM context.

Bind to an EntitySet

As of SP1, we improved binding support for EntitySets. EntitySets are aggregating, un-ordered collections. That means every time an entity is loaded by your DomainContext it will be added to its corresponding EntitySet. Binding to an EntitySet will give you a great view of every entity of a specific type your DomainContext knows about. Adding to or removing from an EntitySet will result in calls to the insert and delete operations being invoked when you submit changes to your DomainService.

Making an EntitySet available in your view model would look like this.

   public EntitySet<SampleEntity> EntitySet
  {
    get { return this.Context.SampleEntities; }
  }

Bind to an EntityCollection

In SP1, we also improved binding support for EntityCollections. EntityCollections are collections of entities associated with a specific Entity. In a manner similar to the EntitySet, an EntityCollection will be updated as new entities are loaded into your DomainContext. Each will be added to the EntityCollection of the Entity it is associated with. Adding and removing from an EntityCollection will only update the association. Most of the time, this results in an update operation being invoked when you submit changes.

Since EntityCollections are tied to specified Entities, having a property on your view model seems like an uncommon case. Nevertheless, making an EntityCollection available in your view model would look like this.

   public EntityCollection<SampleEntity> EntityCollection
  {
    get { return this.CurrentEntity.AssociatedEntities; }
  }

Bind to an EntityList

EntityList is a type new to SP1 and can be found in Microsoft.Windows.Data.DomainServices in the Toolkit. An EntityList is an observable collection backed by an EntitySet. The Source property on the EntityList defines the entities it contains, and it will not update as new entities are loaded into your DomainContext. It will update if entities it contains are deleted from the EntitySet or when entities are added or removed from its Source collection. Adding to an EntityList will behave in one of two ways. If the entity already exists in the backing EntitySet, then it is just added to the list. If it does not exist, then it will be added to the EntitySet as well. Removing from the EntityList will always remove the entity from the backing EntitySet. Binding to an EntityList is a great option when you only want to see a subset of the entities your DomainContext knows about.

Making an EntityList available in your view model would look like this.

   private EntityList<SampleEntity> _entityList;
  public EntityList<SampleEntity> EntityList
  {
    get
    {
      if (this._entityList == null)
      {
        this._entityList = new EntityList<SampleEntity>(
          this.Context.SampleEntities);
      }
      return this._entityList;
    }
  }

  private void LoadSampleEntities()
  {
    this.EntityList.Source =
      this.Context.Load(this.Context.GetAllEntitiesQuery()).Entities;
  }

Bind to an ICollectionView

In case you’re not familiar with the ICollectionView interface, it’s used by a number of components (DataGrid, DataForm, etc.) as a view over a source collection. For example, when you bind DataGrid.ItemsSource to a collection, it will create a collection view behind the scenes to interact with. Instead of just having the control instantiate a view behind the scenes, you have the option of making the ICollectionView available for binding directly from your view model.

It may not be readily apparent why you’d do this, but as you did into the interface, you’ll noticed it has a number of properties for defining how the view presents the source collection. You can control the sorting, grouping, and filtering as well as which item is selected; all from the ICollectionView.

In Silverlight, most collection view implementations are internal. Fortunately, there’s an easy way of letting the framework instantiate the correct view for the collection that uses the CollectionViewSource.

   private static ICollectionView CreateView(IEnumerable source)
  {
    CollectionViewSource cvs = new CollectionViewSource();
    cvs.Source = source;
    return cvs.View;
  }

Making an ICollectionView available in your view model would look like this.

   private ICollectionView _collectionView;
  public ICollectionView CollectionView
  {
    get
    {
      if (this._collectionView == null)
      {
        this._collectionView = CreateView(this.Context.SampleEntities);
      }
      return this._collectionView;
    }
  }

The downside of using this approach is that all the existing collection view implementations only operate over the in-memory collection. That means you have to pull all the data to Silverlight before you apply sorting or filtering.

Bind to a DomainCollectionView

To address the limitations of existing ICollectionView implementations we’ve added the DomainCollectionView in SP1 in Microsoft.Windows.Data.DomainServices in the Toolkit. It is designed to allow for asynchronous sorting, grouping, and paging, and works with all the controls that use the collection view interfaces. This enables you to page over data on your server using the core data controls.

The setup for a DomainCollectionView is slightly more complicated than some of these other options. This is because it requires load callbacks as well as a source collection. These callbacks can be implemented just like any other load operation in your view model.

   private LoadOperation<SampleEntity> LoadSampleEntities()
  {
    return this.Context.Load(
      this.Context.GetAllEntitiesQuery().SortPageAndCount(
        this.DomainCollectionView));
  }

  private void OnLoadSampleEntitiesCompleted(LoadOperation<SampleEntity> op)
  {
    if (op.HasError)
    {
      // TODO: handle errors
      op.MarkErrorAsHandled();
    }
    else if (!op.IsCanceled)
    {
      this.EntityList.Source = op.Entities;

      if (op.TotalEntityCount != -1)
      {
        this.DomainCollectionView.SetTotalItemCount(op.TotalEntityCount);
      }
    }
  }

With callbacks defined, making a DomainCollectionView available in your view model would look like this.

   private DomainCollectionView<SampleEntity> _domainCollectionView;
  public DomainCollectionView<SampleEntity> DomainCollectionView
  {
    get
    {
      if (this._domainCollectionView == null)
      {
        this._domainCollectionView =
          new DomainCollectionView<SampleEntity>(
            new DomainCollectionViewLoader<SampleEntity>(
              this.LoadSampleEntities,
              this.OnLoadSampleEntitiesCompleted),
            this.EntityList);
      }
      return this._domainCollectionView;
    }
  }

This is just enough to get you started with the DomainCollectionView, but it leaves out most of the details. In this next post, I go much more in-depth and explain the design and core API.

https://blogs.msdn.com/b/kylemc/archive/2010/12/02/introducing-an-mvvm-friendly-domaindatasource-the-domaincollectionview.aspx

Are there other options?

There are always other options, but I’m not sure I’d recommend using them. One common alternative would be to make the property types of these collections their respective interfaces (for instance IEnumerable or ICollectionView). This can reduce coupling and give you more flexibility. Also, since most Silverlight controls that bind to collections are just looking for interfaces, the impact is negligible.

If you have other suggestions, I’d love to hear them. Hope this overview helps.