问题
I am attempting to write a SortableBindingList that I can use for my application. I have found lots of discussion about how to implement basic sorting support so that the BindingList will sort when used in the context of a DataGridView or some other bound control including this post from StackOverflow:
DataGridView sort and e.g. BindingList<T> in .NET
This is all very helpful and I have implemented the code, tested, etc. and it's all working, but in my particular situation, I need to be able to support a simple call to Sort() and have that call use the default IComparable.CompareTo() to do the sorting, rather than making a call to ApplySortCore(PropertyDescriptor, ListSortDirection).
The reason is because I have quite a great deal of code that's depending on the Sort() call because this particular class originally inherited from List and was recently changed to be a BindingList.
So specifically, I have a class called VariableCode and a collection class called VariableCodeList. VariableCode implements IComparable and the logic in there is moderately complex based on several properties, etc...
public class VariableCode : ... IComparable ...
{
public int CompareTo(object p_Target)
{
int output = 0;
//some interesting stuff here
return output;
}
}
public class VariableCodeList : SortableBindingList<VariableCode>
{
public void Sort()
{
//This is where I need help
// How do I sort this list using the IComparable
// logic from the class above?
}
}
I've made a few failed attempts at repurposing the ApplySortCore method in the Sort(), but what keeps thwarting me is that the ApplySortCore expects a PropertyDescriptor to do its sort and I can't figure out how to get that to use the IComparable.CompareTo() logic.
Can someone point me in the right direction?
Many thanks.
EDIT: This is the final code based on Marc's response for future reference.
/// <summary>
/// Sorts using the default IComparer of T
/// </summary>
public void Sort()
{
sort(null, null);
}
public void Sort(IComparer<T> p_Comparer)
{
sort(p_Comparer, null);
}
public void Sort(Comparison<T> p_Comparison)
{
sort(null, p_Comparison);
}
private void sort(IComparer<T> p_Comparer, Comparison<T> p_Comparison)
{
m_SortProperty = null;
m_SortDirection = ListSortDirection.Ascending;
//Extract items and sort separately
List<T> sortList = new List<T>();
this.ForEach(item => sortList.Add(item));//Extension method for this call
if (p_Comparison == null)
{
sortList.Sort(p_Comparer);
}//if
else
{
sortList.Sort(p_Comparison);
}//else
//Disable notifications, rebuild, and re-enable notifications
bool oldRaise = RaiseListChangedEvents;
RaiseListChangedEvents = false;
try
{
ClearItems();
sortList.ForEach(item => this.Add(item));
}
finally
{
RaiseListChangedEvents = oldRaise;
ResetBindings();
}
}
回答1:
Emulating a property just to do the sort is probably overkill.
The first thing to look at is Comparer<T>.Default
. It might, however, turn out that the easiest thing to do is to:
- extract the data into
List<T>
or similar - sort the extracted data
- disable notifications
- reload the data
- re-enable notifications
- send a "reset" message
btw, you should be disabling notifications during your existing sort, too.
public void Sort() {
// TODO: clear your "sort" variables (prop/order)
T[] arr = new T[Count];
CopyTo(arr, 0);
Array.Sort(arr);
bool oldRaise = RaiseListChangedEvents;
RaiseListChangedEvents = false; // <=== oops, added!
try {
ClearItems();
foreach (T item in arr) {
Add(item);
}
} finally {
RaiseListChangedEvents = oldRaise;
ResetBindings();
}
}
回答2:
I had the same problem and this post helped me solve it!
As I implemented this solution (based on Marc's and Paul's code) as an extension and added two simple sort methods, I would like to share it with you:
public static void SortAscending<T, P>(this BindingList<T> bindingList, Func<T, P> sortProperty)
{
bindingList.Sort(null, (a, b) => ((IComparable<P>)sortProperty(a)).CompareTo(sortProperty(b)));
}
public static void SortDescending<T, P>(this BindingList<T> bindingList, Func<T, P> sortProperty)
{
bindingList.Sort(null, (a, b) => ((IComparable<P>)sortProperty(b)).CompareTo(sortProperty(a)));
}
public static void Sort<T>(this BindingList<T> bindingList)
{
bindingList.Sort(null, null);
}
public static void Sort<T>(this BindingList<T> bindingList, IComparer<T> comparer)
{
bindingList.Sort(comparer, null);
}
public static void Sort<T>(this BindingList<T> bindingList, Comparison<T> comparison)
{
bindingList.Sort(null, comparison);
}
private static void Sort<T>(this BindingList<T> bindingList, IComparer<T> p_Comparer, Comparison<T> p_Comparison)
{
//Extract items and sort separately
List<T> sortList = new List<T>();
bindingList.ForEach(item => sortList.Add(item));//Extension method for this call
if (p_Comparison == null)
{
sortList.Sort(p_Comparer);
}//if
else
{
sortList.Sort(p_Comparison);
}//else
//Disable notifications, rebuild, and re-enable notifications
bool oldRaise = bindingList.RaiseListChangedEvents;
bindingList.RaiseListChangedEvents = false;
try
{
bindingList.Clear();
sortList.ForEach(item => bindingList.Add(item));
}
finally
{
bindingList.RaiseListChangedEvents = oldRaise;
bindingList.ResetBindings();
}
}
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
if (source == null) throw new ArgumentNullException("source");
if (action == null) throw new ArgumentNullException("action");
foreach (T item in source)
{
action(item);
}
}
Hope this is helpful.
来源:https://stackoverflow.com/questions/1063917/bindinglistt-sort-to-behave-like-a-listt-sort