Wednesday, January 19, 2011

Persisting Silverlight DataGrid sort descriptions

I came across this issue recently: how to persist Silverlight DataGrid sort descriptions between changes of the ItemsSource property? The DataGrid on version 4.0 does not expose a direct interface to manipulate the column sort descriptions although it somehow manages them internally. If you want to explicitly manage the column sort descriptions, you must use a PagedCollectionView container, through the SortDescriptions collection.

If you feed a PagedCollectionView to a DataGrid and then let the user change the column sort descriptions through the user interface (by clicking the column headers), the SortDescriptions collection will store the user changes. After realizing this, I devised a very simple strategy to persist the column sort descriptions whenever I needed to refresh the DataGrid:

  • If the data source is a PagedViewCollection, I just make a copy of the old SortDescriptions collection and apply it to the new PagedViewCollection object.
  • If the data source is just an IEnumerable, I create a new PagedViewCollection to wrap it and do the same as the previous point.

To make my life a bit easier, I created a very simple helper class with two private members:


private DataGrid dataGrid = null;
private PagedCollectionView pagedView = null;

The constructor simply stores the target DataGrid object reference:

public PersistDataGridSort(DataGrid dataGrid)
{
    this.dataGrid = dataGrid;
}

The bulk of the work is done in the SetItemsSource function that takes an object as parameter. This must be either an IEnumerable or a PagedCollectionView:

public void SetItemsSource(object collection)
{
    SortDescriptionCollection sortDescriptions = null;

    if(collection is PagedCollectionView)
    {
        if(pagedView != null)
        {
            sortDescriptions = new SortDescriptionCollection();

            foreach(SortDescription sortDescr in pagedView.SortDescriptions)
            {
                sortDescriptions.Add(sortDescr);
            }
        }
        pagedView = collection as PagedCollectionView;
        pagedView.SortDescriptions.Clear();
    }
    else if(collection is IEnumerable)
    {
        IEnumerable enumerable = collection as IEnumerable;

        if(pagedView != null)
            sortDescriptions = pagedView.SortDescriptions;
        pagedView = new PagedCollectionView(enumerable);
    }
    else
        throw new ArgumentException("Collection must be either a PagedCollectionView or an IEnumerable.");

    // Set the data grid's source
    dataGrid.ItemsSource = pagedView;

    // Reinstate the old sort descriptions
    if(sortDescriptions != null)
    {
        foreach(SortDescription sortDescr in sortDescriptions)
            pagedView.SortDescriptions.Add(sortDescr);
    }
}

To use this class, just create an instance using the target DataGrid and set its data source by calling this class' SetItemsSource method. Have fun!

No comments:

Post a Comment