CollectionView.DeferRefresh() : My new best friend

Well, maybe not best friend but its a nice function.  When working with bound collections in WPF you often end up dealing with a CollectionView.  This is the MSDN documentation description of a CollectionView :

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.

As stated above the main use of the CollectionView is to enable modifying the visible collection without actually changing the underlying data.  In the application I am working on I let the user change what a ListBox is sorted by.  This is the code I originally had:

    1: ICollectionView dataView = CollectionViewSource.GetDefaultView(listBox.ItemsSource);
    2: dataView.SortDescriptions.Clear();
    3: SortDescription sd = new SortDescription(newField, ListSortDirection.Ascending);
    4: dataView.SortDescriptions.Add(sd);

The problem with this code is that it causes the view to refresh twice! The Clear and Add function both trigger a SortDescriptionsChanged event which leads to a Refresh of the view.  This problem becomes worse when you are also adding or changing filter in addition to sort descriptions and your collection is very large.  This could visibly slow you application.

This is where my friend DeferRefresh comes in.  If you change the code above to this:

    1: ICollectionView dataView = CollectionViewSource.GetDefaultView(listBox.ItemsSource);
    2: using (dataView.DeferRefresh())
    3: {
    4:     dataView.SortDescriptions.Clear();
    5:     SortDescription sd = new SortDescription(newField, ListSortDirection.Ascending);
    6:     dataView.SortDescriptions.Add(sd);
    7: }

 

Now the CollectionView will only be refreshed once! All the methods inside the using block will no longer cause a refresh, they will just indicate that a refresh is needed. Then when the code leaves the using block the method EndDefer() is called which just refreshes the CollectionView if needed.