Sortable Observable Collection in C#
Sorting outside the collection
protected override void OnNavigatedTo(NavigationEventArgs e) { if (Settings.AscendingSort.Value) { App.PictureList.Pictures = new ObservableCollection<Models.Picture>(App.PictureList.Pictures.OrderBy(x => x.DateTaken)) as System.Collections.IList; Recent.ItemsSource = App.PictureList.Pictures; } else { App.PictureList.Pictures = new ObservableCollection<Models.Picture>(App.PictureList.Pictures.OrderByDescending(x => x.DateTaken)) as System.Collections.IList; Recent.ItemsSource = App.PictureList.Pictures; }
}
Sort on the XAML View
http://msdn.microsoft.com/en-us/library/ms742542.aspx
// You can sort the view of the collection rather that sorting the collection itself // xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" <myView.Resources> <CollectionViewSource x:Key="ItemListViewSource" Source="{Binding Itemlist}"> <CollectionViewSource.SortDescriptions> <scm:SortDescription PropertyName="{Binding SortingProperty}" /> </CollectionViewSource.SortDescriptions> </CollectionViewSource> </myView.Resources> And then you can use the CollectionViewSource as ItemSource: ItemsSource="{Binding Source={StaticResource ItemListViewSource}}"
Sorted Observable Collection
namespace SortedCollection { /// <summary> /// SortedCollection which implements INotifyCollectionChanged interface and so can be used /// in WPF applications as the source of the binding. /// </summary> /// <author>consept</author> public class SortedObservableCollection<TValue> : SortedCollection<TValue>, INotifyPropertyChanged, INotifyCollectionChanged { public SortedObservableCollection() : base() { } public SortedObservableCollection(IComparer<TValue> comparer) : base(comparer) { } // Events public event NotifyCollectionChangedEventHandler CollectionChanged; public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (this.CollectionChanged != null) { this.CollectionChanged(this, e); } } private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index) { this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index)); } private void OnCollectionChanged(NotifyCollectionChangedAction action, object oldItem, object newItem, int index) { this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index)); } private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index, int oldIndex) { this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index, oldIndex)); } private void OnCollectionReset() { this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { if (this.PropertyChanged != null) { this.PropertyChanged(this, e); } } private void OnPropertyChanged(string propertyName) { this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } public override void Insert(int index, TValue value) { base.Insert(index, value); this.OnPropertyChanged("Count"); this.OnPropertyChanged("Item[]"); this.OnCollectionChanged(NotifyCollectionChangedAction.Add, value, index); } public override void RemoveAt(int index) { var item = this[index]; base.RemoveAt(index); this.OnPropertyChanged("Item[]"); this.OnPropertyChanged("Count"); this.OnCollectionChanged(NotifyCollectionChangedAction.Remove, item, index); } public override TValue this[int index] { get { return base[index]; } set { var oldItem = base[index]; base[index] = value; this.OnPropertyChanged("Item[]"); this.OnCollectionChanged(NotifyCollectionChangedAction.Replace, oldItem, value, index); } } public override void Clear() { base.Clear(); OnCollectionReset(); } } }
Example
/* * 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 }