Search code examples
c#sortingcollectionviewsource

CollectionViewSource sort algorithm


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?


Solution

  • 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.