using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Linq.Expressions; using System.Windows.Data; namespace Developpez.Dotnet.Windows.Collections { /// /// Fournit des méthodes d'extension pour la mise en forme d'une ICollectionView /// public static class CollectionViewShaper { /// /// Renvoie un objet permettant de configurer la mise en forme pour la collection spécifiée. /// ///Collection pour laquelle on veut configurer la mise en forme ///Type des éléments de la collection ///Un objet permettant de configurer la mise en forme pour la collection. /// La mise en forme sera appliquée à la vue par défaut de la collection, obtenue /// avec CollectionViewSource.GetDefaultView public static CollectionViewShaper ShapeView(this IEnumerable source) { var view = CollectionViewSource.GetDefaultView(source); return new CollectionViewShaper(view); } /// /// Renvoie un objet permettant de configurer la mise en forme pour la ICollectionView spécifiée. /// /// Type des éléments de la collection /// ICollectionView pour laquelle on veut configurer la mise en forme /// Un objet permettant de configurer la mise en forme pour la ICollectionView spécifiée. public static CollectionViewShaper Shape(this ICollectionView view) { return new CollectionViewShaper(view); } } /// /// Permet de configurer la mise en forme d'une ICollectionView à l'aide de Linq /// /// Type des éléments de la collection public class CollectionViewShaper { private readonly ICollectionView _view; private Predicate _filter; private readonly List _sortDescriptions = new List(); private readonly List _groupDescriptions = new List(); /// /// Initialise une nouvelle instance de CollectionViewShaper<TSource> /// /// La ICollectionView à mettre en forme public CollectionViewShaper(ICollectionView view) { if (view == null) throw new ArgumentNullException("view"); _view = view; _filter = view.Filter; _sortDescriptions = view.SortDescriptions.ToList(); _groupDescriptions = view.GroupDescriptions.ToList(); } /// /// Applique la mise en forme spécifiée à la ICollectionView. /// public void Apply() { using (_view.DeferRefresh()) { _view.Filter = _filter; _view.SortDescriptions.Clear(); foreach (var s in _sortDescriptions) { _view.SortDescriptions.Add(s); } _view.GroupDescriptions.Clear(); foreach (var g in _groupDescriptions) { _view.GroupDescriptions.Add(g); } } } /// /// Réinitialise les groupements de la ICollectionView /// /// L'objet CollectionViewShaper<TSource> public CollectionViewShaper ClearGrouping() { _groupDescriptions.Clear(); return this; } /// /// Réinitialise les tris de la ICollectionView /// /// L'objet CollectionViewShaper<TSource> public CollectionViewShaper ClearSort() { _sortDescriptions.Clear(); return this; } /// /// Réinitialise le filtre de la ICollectionView /// /// L'objet CollectionViewShaper<TSource> public CollectionViewShaper ClearFilter() { _filter = null; return this; } /// /// Réinitialise toute la mise en forme de la ICollectionView (tri, groupement et filtre) /// /// L'objet CollectionViewShaper<TSource> public CollectionViewShaper ClearAll() { _filter = null; _sortDescriptions.Clear(); _groupDescriptions.Clear(); return this; } /// /// Spécifie le filtre à appliquer aux éléments de la ICollectionView. /// /// Prédicat que les éléments doivent vérifier pour apparaître dans les résultats /// L'objet CollectionViewShaper<TSource> public CollectionViewShaper Where(Func predicate) { _filter = o => predicate((TSource)o); return this; } /// /// Indique que les éléments de la ICollectionView doivent être triés par ordre croissant selon la propriété spécifiée. /// /// Type de la clé de tri /// Expression qui spécifie la propriété selon laquelle les éléments sont triés. /// L'objet CollectionViewShaper<TSource> /// Cette méthode remplace les tris existants. Pour ajouter un tri sans remplacer les tris existants, utiliser /// la méthode ThenBy. public CollectionViewShaper OrderBy(Expression> keySelector) { return OrderBy(keySelector, true, ListSortDirection.Ascending); } /// /// Indique que les éléments de la ICollectionView doivent être triés par ordre décroissant selon la propriété spécifiée. /// /// Type de la clé de tri /// Expression qui spécifie la propriété selon laquelle les éléments sont triés. /// L'objet CollectionViewShaper<TSource> /// Cette méthode remplace les tris existants. Pour ajouter un tri sans remplacer les tris existants, utiliser /// la méthode ThenByDescending. public CollectionViewShaper OrderByDescending(Expression> keySelector) { return OrderBy(keySelector, true, ListSortDirection.Descending); } /// /// Indique que les éléments de la ICollectionView doivent être triés par ordre croissant selon la propriété spécifiée. /// /// Type de la clé de tri /// Expression qui spécifie la propriété selon laquelle les éléments sont triés. /// L'objet CollectionViewShaper<TSource> /// Cette méthode ne remplace pas les tris existants, mais ajoute un nouveau tri aux tris existants. Pour remplacer /// les tris existants, utiliser la méthode OrderBy. public CollectionViewShaper ThenBy(Expression> keySelector) { return OrderBy(keySelector, false, ListSortDirection.Ascending); } /// /// Indique que les éléments de la ICollectionView doivent être triés par ordre décroissant selon la propriété spécifiée. /// /// Type de la clé de tri /// Expression qui spécifie la propriété selon laquelle les éléments sont triés. /// L'objet CollectionViewShaper<TSource> /// Cette méthode ne remplace pas les tris existants, mais ajoute un nouveau tri aux tris existants. Pour remplacer /// les tris existants, utiliser la méthode OrderByDescending. public CollectionViewShaper ThenByDescending(Expression> keySelector) { return OrderBy(keySelector, false, ListSortDirection.Descending); } private CollectionViewShaper OrderBy(Expression> keySelector, bool clear, ListSortDirection direction) { string path = GetPropertyPath(keySelector.Body); if (clear) _sortDescriptions.Clear(); _sortDescriptions.Add(new SortDescription(path, direction)); return this; } /// /// Indique que les éléments de la ICollectionView doivent être groupés selon la propriété spécifiée. /// /// Type de la clé de groupement /// Expression qui spécifie la propriété selon laquelle les éléments sont triés. /// L'objet CollectionViewShaper<TSource> /// Cette ajoute un nouveau groupement aux groupements existants. Pour supprimer les groupements, utiliser /// la méthode ClearGrouping. public CollectionViewShaper GroupBy(Expression> keySelector) { string path = GetPropertyPath(keySelector.Body); _groupDescriptions.Add(new PropertyGroupDescription(path)); return this; } private static string GetPropertyPath(Expression expression) { var names = new Stack(); var expr = expression; while (expr != null && !(expr is ParameterExpression) && !(expr is ConstantExpression)) { var memberExpr = expr as MemberExpression; if (memberExpr == null) throw new ArgumentException("The selector body must contain only property or field access expressions"); names.Push(memberExpr.Member.Name); expr = memberExpr.Expression; } return String.Join(".", names.ToArray()); } } }