May
29
2010

View Model Collection Properties for WCF RIA Services

For the most part combining WCF RIA Services with the MVVM pattern is easy. One area of difficulty is in exposing collections of entities from the ViewModel. This post is going to show some of the current possibilities including my favorite solution, the PagedCollectionView. In two follow up posts I will be discussing some more advanced PagedCollectionView examples and then some future possibilities.

Using LoadOperation.Entities

private IEnumerable<Customer> _customers; 
public IEnumerable<Customer> Customers
{ 
    get {return _customers;}
    private set
    {
        _customers = Customers;
        RaisePropertyChanged("Customers");
    }
}

public void LoadCustomers()
{
    LoadOperation loadOp = this.Context.Load(Context.GetCustomersQuery());
    Customers = loadOp.Entities;
}

Pros

  • Simple, easy to understand.
  • Matches example code from RIA Services documentation.

Cons

  • LoadOperation.Entities is read only, so this is only suitable for read only applications.

Using EntitySet

public IEnumerable<Customer> Customers
{ 
    get {return Context.Customers;}
}

Pros

  • Simple
  • EntitySet does implement INotifyCollectionChanged so as it is updated the UI will be automatically refreshed.

Cons

  • Exposing the EntitySet to the view, even hidden behind IEnumerable, gives the view too much access.
  • Binding to the EntitySet means that there is no ability to filter, everything in the EntitySet will be bound to the UI.
  • The built in add/remove abilities of the DataGrid and DataForm do not support the EntitySet

Using ObservableCollection

private ObservableCollection<Customer> _customers; 
public ObservableCollection<Customer> Customers
{ 
    get {return _customers;}
    private set
    {
        _customers = Customers;
        RaisePropertyChanged("Customers");
    }
}

public void LoadCustomers()
{
    this.Context.Load(Context.GetCustomersQuery(), LoadCustomersCompleted, null);
}

private void LoadCustomersCompleted(LoadOperation<Customer> lo)
{
    Customers = new ObservableCollection<Order>(Context.Customers);
}

Pros

  • ObservableCollection is not read only so this code is not limited to read only applications.
  • ObservableCollection does implement INotifyCollectionChanged so as it is updated the UI will be automatically refreshed.

Cons

  • Every insert, delete, clear, detach, attach, and load within the ViewModel has to manually keep the ObservableCollection in synch. This makes it easy to get into situations where the ObservableCollection gets out of synch with the DomainContext. The worst case scenario here is that a deleted entity gets re-added as a new entity accidently because it hadn’t been removed from the ObservableCollection.
  • ObservableCollection implements IList. This means that the built in add and remove for both the DataGrid and DataForm will be enabled even though any entities added or removed directly to the ObservableCollection will not be added or removed from the EntitySet.

Using an ICollectionView

What is ICollectionView?

Marlon Grech has a good primer on the ICollectionView, I suggest you go and read his entry on them and then come back.

Have a good read? Great, so now you know what ICollectionView does. Unfortunately, the classes demonstrated by Marlon are marked as internal in Silverlight so we can’t use them. Fortunately, we did get a consolation prize back in Silverlight 3: PagedCollectionView.

Using PagedCollectionView (PCV)

private PagedCollectionView _customers; 
public PagedCollectionView Customers
{ 
    get
    {
        if (_customers == null)
            _customers = new PagedCollectionView(Context.Customers);
        return _customers;
    }
}

public void LoadCustomers()
{
    LoadOperation loadOp = this.Context.Load(Context.GetCustomersQuery());
}

Pros

  • PCV automatically refreshes based on the contents of the EntitySet.
  • PCV has full sorting and filtering ability. This will be demonstrated in the second post of this series.

Cons

  • The PCV’s implementations of IEditableCollectionView and IPagedCollectionView are not compatible with the EntitySet. However, the incompatibility is reported by the PCV so the built in add/remove abilities of the DataForm and DataGrid are properly disabled.
  • The PCV is not strongly typed limiting its usefulness inside the ViewModel.
  • ICollectionView includes a “CurrentItem” property which is used by bound list controls. For example, if two comboboxes are sharing the same PagedCollectionView for the ItemsSource then changing the selection in one combobox will cause the selection to change in the second combobox as well.

Conclusion

None of the above options are perfect, but the PagedCollectionView is certainly the best option that we currently have. In my next post I will be discussing the PagedCollectionView in more depth and in the third post I will be discussing what the optimal solution would be.

blog comments powered by Disqus

Month List