Extending the ObservableCollection to add navigation methods such as MoveFirst, MoveNext, MoveLast, and MovePrevious.

September 25th, 2009

Recently, I had the need to navigate a list by using methods such as MoveFirts, MovePrevious, MoveNext, and MoveLast while at the same time keeping track of its current location to notify the user where they are at in the list.

Enter the ICollectionView.  “You can think of a collection view as a layer on top of a binding source collection that allows you to navigate and display the collection based on sort, filter, and group queries, all without having to manipulate the underlying source collection itself.”, says the MSDN documentation. The ICollectionView supports filtering, sorting, grouping, selection, and navigation.

Now the most common way this is used is by creating your collection, populating it with data, then creating an ICollectionView instance from your collection, and then start sorting, filtering, grouping, etc.  The following code show some examples of how to use the ICollectionView.

//get the view
List<MyObject> myList = new List<MyObject>();   
ICollectionView view = CollectionViewSource.GetDefaultView(myList);
 
//filtering
view.Filter = delegate(object item)
{return item.Contains(searchText);};
 
//sorting
view.SortDescriptions.Add(new SortDescription("LastName", direction));
 
//grouping
view.GroupDescriptions.Add(new PropertyGroupDescription("State"));
 
//selection
view.CurrentItem

But I didn’t want to do this every time I had a collection of data I wanted to navigate. I wanted a single generic collection class that encapsulated all this functionality. So I decided to extend the ObservableCollection to allow for this functionality. So the first thing I need to do is create my class, inherit from ObservableCollection, and then create my constructors.

public class MyObservableCollection<T> : ObservableCollection<T>
{
    public MyObservableCollection(List<T> list)
        : base(list)
    {
    }
 
    public MyObservableCollection(IEnumerable<T> collection)
        : base(collection)
    {
    }
}

Next I want to create my method to return my instance of ICollectionView.

private System.ComponentModel.ICollectionView GetDefaultView()
{
    return System.Windows.Data.CollectionViewSource.GetDefaultView(this);
}

Now, lets create a property to retrieve the currently selected item in the list.

public int CurrentPosition
{
    get
    {
        return GetDefaultView().CurrentPosition;
    }
}

Now lets create our four methods for navigating the items in the collection.

public void MoveFirst()
{
    GetDefaultView().MoveCurrentToFirst();
}
 
public void MovePrevious()
{
    GetDefaultView().MoveCurrentToPrevious();
}
 
public void MoveNext()
{
    GetDefaultView().MoveCurrentToNext();
}
 
public void MoveLast()
{
    GetDefaultView().MoveCurrentToLast();
}

Now, lets use our new collection. First start off by creating and instance of your custom collection.

MyObservableCollection<MyObject> ProgressItemsList = 
new MyObservableCollection<MyObject>(data);

In this example I am using a WPF Ribbon to hold my navigation controls, and commanding to execute the navigation methods. The center label maintains the current position and the count of the number of items in the collection.

ribbon_navigation

So now, when I click the Next button I first need to check whether or not I can move to the next record in the command’s CanExecute event.

private bool CanMoveNext(object parameter)
{
    bool canExecute = false;
 
    if (ProgressItemsList != null)
    {
        int currentPosition = ProgressItemsList.CurrentPosition;
        int lastIndex = ProgressItemsList.Count - 1;
 
        canExecute = currentPosition < lastIndex;
    }
 
    return canExecute;
}

If I can move to the next record, then execute the Execute method of the command.

private void MoveNext(object sender)
{
    ProgressItemsList.MoveNext();
}

That is it, and because this is an ObservableCollection, all the changes are notified back to the UI for you automatically. Now you can extend your custom collection even more to customize your sorting, filtering and grouping.

  • John

    Hello, very nice but it would be really nice to get a working sample so that I can start play around with it right away…

  • http://link Alex38

    Can this be built into the engine? ,