Спасибо, Рэйчел, ваше решение дало мне подсказку, но, тем не менее, ваше решение - ответ, потому что я могу вручную вызывать метод Sort всякий раз, когда меняю свойство Order, но я хотел, чтобы оно было автоматическим. В итоге я получаю динамическую версию вашего кода.
На основании Рэйчел я подошла к этому решению.
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
public ObservableCollectionEx() : base() { }
public ObservableCollectionEx(List<T> l) : base(l) { }
public ObservableCollectionEx(IEnumerable<T> l) : base(l) { }
Func<IEnumerable<T>,IEnumerable<T>> sortFunction;
Action reset;
#region IndexOf
/// <summary>
/// Returns the index of the first object which meets the specified function
/// </summary>
/// <param name="keySelector">A bool function to compare each Item by</param>
/// <returns>The index of the first Item which matches the function</returns>
public int IndexOf(Func<T , bool> compareFunction)
{
return Items.IndexOf(Items.FirstOrDefault(compareFunction));
}
#endregion IndexOf
#region Sorting
/// <summary>
/// Sorts the items of the collection in ascending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
public void SetSort<TKey>(Func<T , TKey> keySelector)
{
sortFunction = list => list.OrderBy(keySelector);
InternalSort();
reset = () => SetSort(keySelector);
}
/// <summary>
/// Sorts the items of the collection in descending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
public void SetSortDescending<TKey>(Func<T , TKey> keySelector)
{
sortFunction = list => list.OrderByDescending(keySelector);
InternalSort();
reset = () => SetSortDescending(keySelector);
}
/// <summary>
/// Sorts the items of the collection in ascending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
/// <param name="comparer">An <see cref="IComparer{T}"/> to compare keys.</param>
public void SetSort<TKey>(Func<T , TKey> keySelector , IComparer<TKey> comparer)
{
sortFunction = list => list.OrderBy(keySelector , comparer);
InternalSort();
reset = () => SetSort(keySelector , comparer);
}
/// <summary>
/// Sorts the items of the collection in descending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
/// <param name="comparer">An <see cref="IComparer{T}"/> to compare keys.</param>
public void SetSortDescending<TKey>(Func<T , TKey> keySelector , IComparer<TKey> comparer)
{
sortFunction = list => list.OrderByDescending(keySelector , comparer);
InternalSort();
reset = () => SetSortDescending(keySelector , comparer);
}
/// <summary>
/// Moves the items of the collection so that their orders are the same as those of the items provided.
/// </summary>
private void InternalSort()
{
UpdateTracking(null , Items.ToList());
}
private void MoveItemToItsLocation(T item)
{
var sortListCache = sortFunction(Items).ToList();
Move(IndexOf(item) , sortListCache.IndexOf(item));
}
#endregion Sorting
public void UpdateTracking(IEnumerable<T> oldItems , IEnumerable<T> newItems)
{
if (sortFunction == null) return;
PropertyChangedEventHandler changeTracker = (o , change) => { MoveItemToItsLocation((T)o); };
Action<T> attachChangeTracker = o => o.ExecuteOnCast<INotifyPropertyChanged>(x => x.PropertyChanged += changeTracker);
Action<T> detachChangeTracker = o => o.ExecuteOnCast<INotifyPropertyChanged>(x => x.PropertyChanged -= changeTracker);
var greeting = new[] { attachChangeTracker , MoveItemToItsLocation };
var farwell = new[] { detachChangeTracker };
oldItems.ForEach(detachChangeTracker);
newItems.ForEach(attachChangeTracker , MoveItemToItsLocation);
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
base.OnCollectionChanged(e);
switch (e.Action) {
case NotifyCollectionChangedAction.Add:
case NotifyCollectionChangedAction.Remove:
case NotifyCollectionChangedAction.Replace:
UpdateTracking(e.OldItems.SafeGet(x => x.Cast<T>()) , e.NewItems.SafeGet(x => x.Cast<T>()));
break;
case NotifyCollectionChangedAction.Reset:
UpdateTracking(Items.ToList() , null);
if (reset != null)
reset();
break;
default:
break;
}
}
}
Я только внес небольшое изменение, чтобы оно следовало за изменениями в базовой коллекции, поэтому она будет автоматически сортироваться после любых изменений, внесенных в базовую коллекцию или любой элемент в базовой коллекции.