I have a generic
List<MyClass>
where MyClass
has a property InvoiceNumber
which contains values such as:
200906/1
200906/2
..
200906/10
200906/11
200906/12
My list is bound to a
BindingList<T>
which supports sorting with linq:
protected override void ApplySortCore(
PropertyDescriptor property, ListSortDirection direction)
{
_sortProperty = property;
_sortDirection = direction;
var items = this.Items;
switch (direction)
{
case ListSortDirection.Ascending:
items = items.OrderByDescending(x => property.GetValue(x)).ToList();
break;
case ListSortDirection.Descending:
items = items.OrderByDescending(x => property.GetValue(x)).ToList();
break;
}
this.Items = items;
}
However the default comparer sorts (as supposed) like this:
200906/1
200906/10
200906/11
200906/12
200906/2
which is nasty in this case.
Now I want to use my own IComparer<T>
with this. It looks like this:
public class MyComparer : IComparer<Object>
{
public int Compare(Object stringA, Object stringB)
{
String[] valueA = stringA.ToString().Split('/');
String[] valueB = stringB.ToString().Split('/');
if(valueA .Length != 2 || valueB .Length != 2)
return String.Compare(stringA.ToString(), stringB.ToString());
if (valueA[0] == valueB[0])
{
return String.Compare(valueA[1], valueB[1]);
}
else
{
return String.Compare(valueA[0], valueB[0]);
}
}
}
and changed the ApplySortCore
code to use this IComparer
:
case ListSortDirection.Ascending:
MyComparer comparer = new MyComparer();
items = items.OrderByDescending(
x => property.GetValue(x), comparer).ToList();
break;
When I debug my code, I see that MyComparer.Compare(object, object)
is called multiple times and returns the right values (-1, 0, 1) for a compare method.
But my list is still sorted the "wrong" way. Am I missing something? I have no clue.
Your comparer looks wrong to me. You're still just sorting in the default text ordering. Surely you want to be parsing the two numbers and sorting based on that:
public int Compare(Object stringA, Object stringB)
{
string[] valueA = stringA.ToString().Split('/');
string[] valueB = stringB.ToString().Split('/');
if (valueA.Length != 2 || valueB.Length != 2)
{
stringA.ToString().CompareTo(stringB.ToString());
}
// Note: do error checking and consider i18n issues too :)
if (valueA[0] == valueB[0])
{
return int.Parse(valueA[1]).CompareTo(int.Parse(valueB[1]));
}
else
{
return int.Parse(valueA[0]).CompareTo(int.Parse(valueB[0]));
}
}
(Note that this doesn't sit well with your question stating that you've debugged through and verified that Compare is returning the right value - but I'm afraid I suspect human error on that front.)
Additionally, Sven's right - changing the value of items
doesn't change your bound list at all. You should add:
this.Items = items;
at the bottom of your method.