Sorts and filters on ObservableCollection

Using the ObservableCollection<T> collection is a very common practice among UI developers. Added to the fact that they allow easy UI updates, they also allow sorting and filtering operations via CollectionViews. This post describes a pattern linking an ObservableCollection to sortable and filterable ListCollectionViews, which are themselves displayed in the UI.

image

The pattern works as follows:

 

1. Define a get/set property for the source ObservableCollection, and a read-only property for each view of the source

ObservableCollection<Personne> _sampleData;

public ObservableCollection<Personne> SampleData
{
    get { return _sampleData; }
    set
    {
        _sampleData = value;
        …
    }

}

ListCollectionView _cvSampleDataSortAge, _cvSampleDataFilterAge;
public CollectionView CVSampleDataSortAge { get { return _cvSampleDataSortAge; } }
public CollectionView CVSampleDataFilterAge { get { return _cvSampleDataFilterAge; } }

2. When the source ObservableCollection is set :

a. Instanciate the ListCollectionViews

b. On each one of them add if necessary:

                                                                          i.  SortDescription(s) for views that involve sorting

                                                                         ii. Filter predicates for views that filter

c. Raise the PropertyChanged event on the source ObservableCollection property and on each view.

set
{

    _sampleData = value;

    // Instantiates the views, SortDescriptions, filters…

    _cvSampleDataSortAge = new ListCollectionView(_sampleData);

    _cvSampleDataSortAge.SortDescriptions.Add(new SortDescription("Age",
ListSortDirection.Ascending));

    _cvSampleDataFilterAge = new ListCollectionView(_sampleData);

    _cvSampleDataFilterAge.Filter += new Predicate<object>(FiltreAge);

    // Raises PropertyChanged events on the properties

    OnNotifyPropertyChanged("SampleData");

    OnNotifyPropertyChanged("CVSampleDataSortAge");

    OnNotifyPropertyChanged("CVSampleDataFilterAge");

    // Synchronises with the current item (optional)

    var cv = CollectionViewSource.GetDefaultView(_sampleData);

    cv.CurrentChanged += new EventHandler(delegate

        {

            _cvSampleDataSortAge.MoveCurrentTo(cv.CurrentItem);

            _cvSampleDataFilterAge.MoveCurrentTo(cv.CurrentItem);

        });

}

3. In your XAML UI code, bind to the ListCollectionView properties

<ListBox ItemsSource="{Binding Path=CVSampleDataSortAge}"/>

The views are automatically updated in regards to the source’s composition (as defined by NotifyCollectionChangedAction). Changes to a property of an element contained within an ObservableCollection will not trigger an update of the views. This functionality, as described in a previous post, can be implemented using another type of Collection which we’ll explore in further details in the next post.

Some more details

CollectionViews separate the presentation of a Collection, from the source collection itself. This allows (for example) scenarios where an ObservableCollection can be filtered and sorted on screen, without having to modify the source Collection or having to handle temporary collections which would have to be kept in sync with the source.

 

 

image

CollectionViewDemo_EN.zip