May
29
2010
In the previous post I showed some of the ways that collections of entities can be exposed from your ViewModel. The load examples I showed was relatively simple as it demonstrated a simple load with no ordering or filtering and there was only a single load. In a more realistic example where ordering or filtering is being used and the EntitySet cannot be cleared between loads then only the PagedCollectionView and ObservableCollection will work. In this post, I will show a more full example of how you can combine WCF RIA Services, ViewModel, and PagedCollectionView to fully support filtering, sorting, and multiple loads.
private PagedCollectionView _customers;
public PagedCollectionView Customers
{
get
{
if (_customers == null)
{
_customers = new PagedCollectionView(Context.Customers);
_customers.SortDescriptions.Add(new SortDescription("Name", ListSortDescription.Ascending));
}
return _customers;
}
}
public void LoadCustomersByState(string state)
{
var qry = this.Context.GetCustomersQuery().Where(c=>c.State == State).OrderBy(c=>c.Name);
LoadOperation loadOp = this._customerContext.Load(qry);
Customers.Filter = c=>((Customer)c).State == state;
}
When the PagedCollectionView was created, a SortDescription was set, this ensures that the PagedCollectionView will always be correctly sorted. The load is not clearing the EntitySet so it is possible for customers from multiple states to be loaded at the same time but the filter on the PagedCollectionView makes sure that only the currently selected state’s customers is being shown.
It is possible to get the same effect using the ObservableCollection but it requires refilling the ObservableCollection every time an entity is updated or inserted into the EntitySet which can cause problems for the bound UI controls.
The above example shows how to keep the load in sync with the PagedCollectionView, here is a second scenario where the load is separated from what is being shown in the UI:
private PagedCollectionView _customers;
public PagedCollectionView Customers
{
get
{
if (_customers == null)
{
_customers = new PagedCollectionView(Context.Customers);
_customers.SortDescriptions.Add(new SortDescription("Name", ListSortDescription.Ascending));
_customers.Filter = c=> (string.IsNullEmpty(SelectedState) || ((Customer)c).State == SelectedState);
}
return _customers;
}
}
private string _selectedState = null;
public string SelectedState
{
get {return _selectedState;}
set
{
_selectedState = value;
Customers.Refresh(); //this lets the PCV know that the filter changed
RaisePropertyChanged(“SelectedState”);
}
public void LoadCustomers()
{
var qry = this.Context.GetCustomersQuery().OrderBy(c=>c.Name);
LoadOperation loadOp = this._customerContext.Load(qry);
}
Wrap Up
The most important thing that the PagedCollectionView gains you is a clear separation of concerns within the ViewModel. Any business logic code adding, deleting, or updating entities does need to worry about updating the UI, that is taken care of by the PagedCollectionView which is monitoring the EntitySet itself for those changes. The only thing that the PagedCollectionView cannot detect for itself is when the any external values used in the Filter are modified so you do need to keep track of that and call the Refresh method whenever that happens. Other then that, in the ViewModels that the above code would be a part of no other reference to the PagedCollectionView properties would be necessary. The same can not be said for any of the other options that are available. In the last part of this series I will be discussing what is coming in the future.