using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
namespace Developpez.Dotnet.Collections
{
///
/// Représente une liste supportant les scénarios de liaison de données
/// ainsi que le tri
///
/// Type des éléments de la liste
public class SortableBindingList : BindingList
{
#region Static sort implementation
private static readonly Dictionary> _comparisons;
static SortableBindingList()
{
_comparisons = new Dictionary>();
}
private static Comparison GetComparison(PropertyDescriptor prop, ListSortDirection direction)
{
Comparison comparison;
lock (_comparisons)
{
if (!_comparisons.TryGetValue(prop, out comparison))
{
comparison = CreateComparison(prop);
_comparisons[prop] = comparison;
}
}
if (direction == ListSortDirection.Descending)
comparison = comparison.Reverse();
return comparison;
}
private static Comparison CreateComparison(PropertyDescriptor prop)
{
var a = Expression.Parameter(typeof (T), "a");
var b = Expression.Parameter(typeof(T), "b");
var comparerType = typeof (Comparer<>).MakeGenericType(prop.PropertyType);
var comparerProperty = comparerType.GetProperty("Default");
var compareMethod = comparerType.GetMethod("Compare");
var comparer = Expression.Property(null, comparerProperty);
var body =
Expression.Call(
comparer,
compareMethod,
Expression.Property(a, prop.Name),
Expression.Property(b, prop.Name));
var lambda = Expression.Lambda>(body, a, b);
return lambda.Compile();
}
#endregion
#region Private data
private bool _isSorted;
private PropertyDescriptor _sortProperty;
private ListSortDirection _sortDirection;
private List _unsortedList;
#endregion
#region Constructors
///
/// Initialise une nouvelle instance de .
///
public SortableBindingList()
{
}
///
/// Initialise une nouvelle instance de avec la liste spécifiée.
///
/// La liste d'éléments à contenir dans la
public SortableBindingList(IList list)
: base(list)
{
}
#endregion
#region BindingList overrides
///
/// Obtient une valeur indiquant si la liste supporte le tri.
///
protected override bool SupportsSortingCore
{
get
{
return true;
}
}
///
/// Trie les éléments de la liste selon la propriété et la direction spécifiées
///
/// La propriété selon laquelle trier la liste
/// La direction selon laquelle trier la liste
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
Debug.Print("ApplySortCore({0}, {1})", prop.Name, direction);
bool raiseEvents = RaiseListChangedEvents;
try
{
RaiseListChangedEvents = false;
var tmpList = Items.ToList();
Comparison comparison = GetComparison(prop, direction);
tmpList.Sort(comparison);
if (_unsortedList == null)
_unsortedList = Items.ToList();
Items.Clear();
foreach (var item in tmpList)
{
Items.Add(item);
}
_isSorted = true;
_sortProperty = prop;
_sortDirection = direction;
}
finally
{
RaiseListChangedEvents = raiseEvents;
}
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
///
/// Obtient une valeur indiquant si la liste est triée
///
protected override bool IsSortedCore
{
get { return _isSorted; }
}
///
/// Retire le tri appliqué avec ApplySortCore.
///
protected override void RemoveSortCore()
{
Debug.Print("RemoveSortCore()");
bool raiseEvents = RaiseListChangedEvents;
try
{
RaiseListChangedEvents = false;
if (_unsortedList != null)
{
Items.Clear();
foreach (var item in _unsortedList)
{
Items.Add(item);
}
}
_isSorted = false;
_sortProperty = null;
_unsortedList = null;
}
finally
{
RaiseListChangedEvents = raiseEvents;
}
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
///
/// Obtient la direction du tri si la liste est triée
///
protected override ListSortDirection SortDirectionCore
{
get { return _sortDirection; }
}
///
/// Obtient la propriété selon laquelle la liste est triée
///
protected override PropertyDescriptor SortPropertyCore
{
get { return _sortProperty; }
}
///
/// Insère l'élément spécifié dans la liste à la position spécifiée
///
/// Position à laquelle insérer l'élément
/// Élément à insérer
protected override void InsertItem(int index, T item)
{
Debug.Print("InsertItem({0}, {1})", index, item);
base.InsertItem(index, item);
if (_unsortedList != null)
{
_unsortedList.Add(item);
}
}
///
/// Retire de la liste l'élément qui se trouve à la position spécifiée
///
/// Position de l'élément à retirer
protected override void RemoveItem(int index)
{
Debug.Print("RemoveItem({0})", index);
T item = this[index];
base.RemoveItem(index);
if (_unsortedList != null)
{
_unsortedList.Remove(item);
}
}
///
/// Remplace l'élément à la position spécifiée par l'élément spécifié
///
/// Position de l'élément à remplacer
/// Nouvel élément à placer à cette position
protected override void SetItem(int index, T item)
{
Debug.Print("SetItem({0}, {1})", index, item);
T oldItem = this[index];
base.SetItem(index, item);
if (_unsortedList != null)
{
int idx = _unsortedList.IndexOf(oldItem);
if (idx >= 0)
_unsortedList[idx] = item;
}
}
///
/// Retire tous les éléments de la liste
///
protected override void ClearItems()
{
Debug.Print("ClearItems()");
base.ClearItems();
if (_unsortedList != null)
_unsortedList.Clear();
}
#endregion
}
}