Reputation: 163
How to change the sort algorithm of CollectionViewSource? In fact, i found that the sort algorithm of CollectionViewSource is not stable. And i want to use a stable algorithm on the CollectionViewSource. How can i do that?
Upvotes: 1
Views: 871
Reputation: 4978
I've managed to get a stable sorting using a custom Comparer, but it kinda feels like a big hack...
Just like Benjamin suggested, I get the ListCollectionView from the collection and set its CustomSort property with my custom Comparer. The only difference is that I pass the collection to the Comparer when instantiating it.
private void Sorting(IEnumerable collection)
{
var view = CollectionViewSource.GetDefaultView(collection) as ListCollectionView;
if (view != null)
{
view.CustomSort = new StableComparer(collection);
}
}
Then, in my custom Comparer, I use the collection in the Compare method just to fallback to the items indexes when the comparison returns a zero (they are the same or have the same value).
public class StableComparer : IComparer
{
public IEnumerable Collection { get; set; }
public StableComparer(IEnumerable collection)
{
Collection = collection;
}
public int Compare(object x, object y)
{
IComparable x_Comparable = x as IComparable;
IComparable y_Comparable = y as IComparable;
if (x_Comparable != null && y_Comparable != null)
{
var comparison = x_Comparable.CompareTo(y_Comparable);
// A zero value means x and y are equivalent for sorting, and they could
// be rearranged by an unstable sorting algorithm
if (comparison == 0 && Collection != null)
{
// IndexOf is an extension method for IEnumerable (not included)
var x_Index = Collection.IndexOf(x);
var y_Index = Collection.IndexOf(y);
// By comparing their indexes in the original collection, we get to
// preserve their relative order
if (x_Index != -1 && y_Index != -1)
comparison = x_Index.CompareTo(y_Index);
}
return comparison;
}
return 0;
}
}
I'm still testing this, so I can't guarantee this would work all the time... One problem would be keeping the Collection property inside the Comparer updated, for instance. Or supporting two sort directions.
But I think the idea is clear, though hacky, as I said.
Upvotes: 4
Reputation: 1187
You might want to check out how to implement your custom sorting logic.
In short, set your comparer like this:
private void Sort(object sender, RoutedEventArgs args)
{
BlogPosts posts = (BlogPosts)(this.Resources["posts"]);
ListCollectionView lcv = (ListCollectionView)(CollectionViewSource.GetDefaultView(posts));
lcv.CustomSort = new SortPosts();
}
And implement it like this:
public class SortPosts : IComparer
{
public int Compare(object x, object y)
{
(…)
}
}
Upvotes: 1