I want to know the best way to sort a BindingList without needed to
turn it into a DataTable. Of course, my BindingList is being used
indirectly by a BindingSource.
So, how do I sort a BindingList of my custom business objects? For
instance, when the user clicks on a column header of a DataGridView, I
would like sorting to be handled for me (or to call a custom sort
method I provide).
If this isn't supported, that would be good to know.
Thanks,
Travis
I have a full implementation, but can't access it until tomorrow. Let
me know if you want me to post some of this (although it isn't too
hard).
Marc
public class SortableBindingList<T> : BindingList<T>
{
protected override bool SupportsSortingCore
{
get
{
return true;
}
}
protected override bool IsSortedCore
{
get
{
for (int i = 0; i < Items.Count - 1; ++i)
{
T lhs = Items[i];
T rhs = Items[i + 1];
PropertyDescriptor property = SortPropertyCore;
if (property != null)
{
object lhsValue = lhs == null ? null :
property.GetValue(lhs);
object rhsValue = rhs == null ? null :
property.GetValue(rhs);
int result;
if (lhsValue == null)
{
result = -1;
}
else if (rhsValue == null)
{
result = 1;
}
else
{
result =
Comparer.Default.Compare(lhsValue, rhsValue);
}
if (SortDirectionCore ==
ListSortDirection.Descending)
{
result = -result;
}
if (result >= 0)
{
return false;
}
}
}
return true;
}
}
private ListSortDirection sortDirection;
protected override ListSortDirection SortDirectionCore
{
get
{
return sortDirection;
}
}
private PropertyDescriptor sortProperty;
protected override PropertyDescriptor SortPropertyCore
{
get
{
return sortProperty;
}
}
protected override void ApplySortCore(PropertyDescriptor prop,
ListSortDirection direction)
{
sortProperty = prop;
sortDirection = direction;
List<T> list = (List<T>)Items;
list.Sort(delegate(T lhs, T rhs)
{
if (sortProperty != null)
{
object lhsValue = lhs == null ? null :
sortProperty.GetValue(lhs);
object rhsValue = rhs == null ? null :
sortProperty.GetValue(rhs);
int result;
if (lhsValue == null)
{
result = -1;
}
else if (rhsValue == null)
{
result = 1;
}
else
{
result = Comparer.Default.Compare(lhsValue,
rhsValue);
}
if (sortDirection == ListSortDirection.Descending)
{
result = -result;
}
return result;
}
else
{
return 0;
}
});
}
protected override void RemoveSortCore()
{
sortDirection = ListSortDirection.Ascending;
sortProperty = null;
}
}
http://msdn2.microsoft.com/en-us/library/system.componentmodel.ibindinglist.issorted(VS.80).aspx
Marc
That actually leaves a much more efficient implementation, since I am
guarunteed it is sorted given.
Thanks,
Travis
could you please post the multi sort example...thanks in advance!!
Annoyingly, I have a *near* identical block of code "on hand" for some
3.5 LINQ stuff, but alas the gap between "near" and "is" (plus the 3.5
link) is too far to be tweaked quickly...
I'm just trying to seee what I can find... shouldn't bee too long...
Marc
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections;
public class AdvancedList<T> : BindingList<T>, IBindingListView {
protected override bool IsSortedCore {
get { return sorts != null; }
}
protected override void RemoveSortCore() {
sorts = null;
}
protected override bool SupportsSortingCore {
get { return true; }
}
protected override ListSortDirection SortDirectionCore {
get { return sorts == null ? ListSortDirection.Ascending :
sorts.PrimaryDirection; }
}
protected override PropertyDescriptor SortPropertyCore {
get {return sorts == null ? null : sorts.PrimaryProperty;}
}
protected override void ApplySortCore(PropertyDescriptor prop,
ListSortDirection direction) {
ListSortDescription[] arr = {
new ListSortDescription(prop, direction)
};
ApplySort(new ListSortDescriptionCollection(arr));
}
PropertyComparerCollection<T> sorts;
public void ApplySort(ListSortDescriptionCollection
sortCollection) {
bool oldRaise = RaiseListChangedEvents;
RaiseListChangedEvents = false;
try {
PropertyComparerCollection<T> tmp
= new PropertyComparerCollection<T>(sortCollection);
List<T> items = new List<T>(this);
items.Sort(tmp);
int index = 0;
foreach(T item in items) {
SetItem(index++, item);
}
sorts = tmp;
} finally {
RaiseListChangedEvents = oldRaise;
ResetBindings();
}
}
string IBindingListView.Filter {
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
void IBindingListView.RemoveFilter() {
throw new NotImplementedException();
}
ListSortDescriptionCollection IBindingListView.SortDescriptions {
get { return sorts.Sorts; }
}
bool IBindingListView.SupportsAdvancedSorting {
get { return true; }
}
bool IBindingListView.SupportsFiltering {
get { return false; }
}
}
public class PropertyComparerCollection<T> : IComparer<T> {
private readonly ListSortDescriptionCollection sorts;
private readonly PropertyComparer<T>[] comparers;
public ListSortDescriptionCollection Sorts {
get { return sorts; }
}
public PropertyComparerCollection(ListSortDescriptionCollection
sorts) {
if (sorts == null) throw new ArgumentNullException("sorts");
this.sorts = sorts;
List<PropertyComparer<T>> list = new
List<PropertyComparer<T>>();
foreach(ListSortDescription item in sorts) {
list.Add(new PropertyComparer<T>(item.PropertyDescriptor,
item.SortDirection == ListSortDirection.Descending));
}
comparers = list.ToArray();
}
public PropertyDescriptor PrimaryProperty {
get {
return comparers.Length == 0 ? null :
comparers[0].Property;
}
}
public ListSortDirection PrimaryDirection {
get {
return comparers.Length == 0 ? ListSortDirection.Ascending
: comparers[0].Descending ?
ListSortDirection.Descending
: ListSortDirection.Ascending;
}
}
int IComparer<T>.Compare(T x, T y) {
int result = 0;
for (int i = 0; i < comparers.Length; i++) {
result = comparers[i].Compare(x, y);
if (result != 0) break;
}
return result;
}
}
public class PropertyComparer<T> : IComparer<T> {
private readonly bool descending;
public bool Descending { get { return descending; } }
private readonly PropertyDescriptor property;
public PropertyDescriptor Property { get { return property; } }
public PropertyComparer(PropertyDescriptor property, bool
descending) {
if (property == null) throw new
ArgumentNullException("property");
this.descending = descending;
this.property = property;
}
public int Compare(T x, T y) {
// todo; some null cases
int value = Comparer.Default.Compare(property.GetValue(x),
property.GetValue(y));
return descending ? -value : value;
}
}
http://wpfmentor.blogspot.com/2008/12/observable-collections-independent-of.html