Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What causes a WPF ListCollectionView that uses custom sorting to re-sort its items?

Tags:

.net

sorting

wpf

Consider this code (type names genericised for the purposes of example):

// Bound to ListBox.ItemsSource
_items = new ObservableCollection<Item>();

// ...Items are added here ...

// Specify custom IComparer for this collection view
_itemsView = CollectionViewSource.GetDefaultView(_items)
((ListCollectionView)_itemsView).CustomSort = new ItemComparer();

When I set CustomSort, the collection is sorted as I expect.

However I require the data to re-sort itself at runtime in response to the changing of the properties on Item. The Item class derives from INotifyPropertyChanged and I know that the property fires correctly as my data template updates the values on screen, only the sorting logic is not being called.

I have also tried raising INotifyPropertyChanged.PropertyChanged passing an empty string, to see if a generic notification would cause the sorting to be initiated. No bananas.

EDIT In response to Kent's suggestion I thought I'd point out that sorting the items using this has the same result, namely that the collection sorts once but does not re-sort as the data changes:

_itemsView.SortDescriptions.Add(
    new SortDescription("PropertyName", ListSortDirection.Ascending));
like image 318
Drew Noakes Avatar asked Mar 02 '09 10:03

Drew Noakes


2 Answers

With .NET 4.5, WPF added live shaping: https://docs.microsoft.com/en-us/dotnet/framework/wpf/getting-started/whats-new#repositioning-data-as-the-datas-values-change-live-shaping

That allows you to set properties for sorting/grouping/filtering, and if the property value changes, the item is sorted/grouped/filtered again. In your case:

// Bound to ListBox.ItemsSource
_items = new ObservableCollection<Item>();

// ...Items are added here ...

// Add sorting
_itemsView = CollectionViewSource.GetDefaultView(_items)
_itemsView.SortDescriptions.Add(new SortDescription("PropertyName", ListSortDirection.Ascending));

// Enable live sorting
// Note that if you don't add any LiveSortingProperties, it will use SortDescriptions
((ICollectionViewLiveShaping)_itemsView).LiveSortingProperties.Add("PropertyName");
((ICollectionViewLiveShaping)_itemsView).IsLiveSorting = true;
like image 57
Daniel Rose Avatar answered Nov 15 '22 19:11

Daniel Rose


As the accepted answer directs me to, I am able to force single item reposition with code

IEditableCollectionView collectionView = DataGrid.Items;

collectionView.EditItem(changedItem);
collectionView.CommitEdit();

Where changedItem is the view model (the item in the ItemsSource collection).

This way you don't need your items to implement any interfaces like IEditableObject (which in my opinion has very complex and hard to implement contract in some cases).

like image 32
Gman Avatar answered Nov 15 '22 18:11

Gman