Home / WPF / WPF Resources / How to make a Sortable ObservableCollection C#

How to make a Sortable ObservableCollection C#

Time ago i had to implement a sortable observable collection that was able to sort its members based on different parameters.

After long and long searching i found this code, and i report it here so it can be useful for readers too.

You can use the SortableObservableCollection in this way:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public class PersonCollection : SortableObservableCollection
{
    public PersonCollection()
	{
		[...fill collection...]
		this.Sort(x => x.Name, ListSortDirection.Ascending);
	}
}

Source code is the following…

/*
 * samples:
 * //sort ascending
 * MySortableList.Sort(x => x.Name, ListSortDirection.Ascending);
 *
 * //sort descending
 * MySortableList.Sort(x => x.Name, ListSortDirection.Descending);
 */
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

namespace Common.WPF
{ 
    public class SortableObservableCollection<T> : ObservableCollection<T>
    {
        public void Sort<TKey>(Func<T,TKey> keySelector, System.ComponentModel.ListSortDirection direction)
        {
            switch (direction)
            {
                case System.ComponentModel.ListSortDirection.Ascending:
                    {
                        ApplySort(Items.OrderBy(keySelector));
                        break;
                    }
                case System.ComponentModel.ListSortDirection.Descending:
                    {
                        ApplySort(Items.OrderByDescending(keySelector));
                        break;
                    }
            }
        }

        public void Sort<TKey>(Func<T,TKey> keySelector, IComparer<TKey> comparer)
        {
            ApplySort(Items.OrderBy(keySelector, comparer));
        }

        private void ApplySort(IEnumerable<T> sortedItems)
        {
            var sortedItemsList = sortedItems.ToList();

            foreach (var item in sortedItemsList)
            {
                Move(IndexOf(item), sortedItemsList.IndexOf(item));
            }
        }
    }

}

 

6 comments

  1. How to make this class as generic ?
    like
    public class SortableObservableCollection : ObservableCollection where T : EntityObject

  2. Hi there Mesta,

    thanks for the solution.

    I modified you version to be usable within a protable class Library (basically the ListSortDirection is not avaible for me).

    I also created two descants. See below.

    /*
    * samples:
    * //sort ascending
    * MySortableList.Sort(x => x.Name, SortDirection.Ascending);
    *
    * //sort descending
    * MySortableList.Sort(x => x.Name, SortDirection.Descending);
    */

    public enum SortDirection
    {
    Ascending,
    Descending
    }

    public class SortableObservableCollection : ObservableCollection
    {
    #region Consts, Fields, Events

    #endregion

    #region Methods

    public void Sort(Func keySelector, SortDirection direction)
    {
    switch (direction)
    {
    case SortDirection.Ascending:
    {
    applySort(Items.OrderBy(keySelector));
    break;
    }
    case SortDirection.Descending:
    {
    applySort(Items.OrderByDescending(keySelector));
    break;
    }
    }
    }

    public void Sort(Func keySelector, IComparer comparer)
    {
    applySort(Items.OrderBy(keySelector, comparer));
    }

    private void applySort(IEnumerable sortedItems)
    {
    var sortedItemsList = sortedItems.ToList();

    foreach (var item in sortedItemsList)
    {
    Move(IndexOf(item), sortedItemsList.IndexOf(item));
    }
    }

    #endregion
    }

    ///
    /// Provides automatic sorting, when items are added/removed
    ///
    ///
    public class SortedObservableCollection : SortableObservableCollection
    {

    #region Consts, Fields, Events

    private readonly IComparer _comparer;

    #endregion

    #region Methods

    public SortedObservableCollection(IComparer comparer)
    {
    Condition.Requires(comparer, “comparer”).IsNotNull();
    _comparer = comparer;
    }

    protected override void InsertItem(int index, T item)
    {
    base.InsertItem(index, item);
    Sort();
    }

    protected override void RemoveItem(int index)
    {
    base.RemoveItem(index);
    Sort();
    }

    public void Sort()
    {
    Sort(item => item, _comparer);
    }

    #endregion
    }

    ///
    /// Whenever a property of the item changed, a sorting will be issued.
    ///
    ///
    public class SortedObservableCollectionEx : SortedObservableCollection where T : class , INotifyPropertyChanged
    {
    #region Consts, Fields, Events

    #endregion

    #region Methods

    public SortedObservableCollectionEx(IComparer comparer)
    : base(comparer)
    {
    }

    protected override void InsertItem(int index, T item)
    {
    base.InsertItem(index, item);
    if (item != null)
    {
    item.PropertyChanged += handleItemPropertyChanged;
    }
    }

    protected override void RemoveItem(int index)
    {
    T item = this[index];
    if (item != null)
    {
    item.PropertyChanged -= handleItemPropertyChanged;
    }

    base.RemoveItem(index);
    }

    private void handleItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
    Sort();
    }

    #endregion

    }

Leave a Reply

Your email address will not be published.