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());
}
}
}