c# - pudieron - BindingList<T>.Sort() para comportarse como una lista<T>.Sort()
order object list c# (2)
Estoy intentando escribir una SortableBindingList que puedo usar para mi aplicación. He encontrado mucha discusión acerca de cómo implementar el soporte de clasificación básico para que BindingList se clasifique cuando se usa en el contexto de un DataGridView o algún otro control vinculado que incluye esta publicación de StackOverflow:
Ordenamiento de DataGridView y, por ejemplo, BindingList <T> en .NET
Todo esto es muy útil y he implementado el código, probado, etc. y todo funciona, pero en mi situación particular, necesito poder admitir una llamada simple a Sort () y hacer que esa llamada use el IComparable predeterminado. CompareTo () para hacer la clasificación, en lugar de hacer una llamada a ApplySortCore (PropertyDescriptor, ListSortDirection).
La razón es porque tengo una gran cantidad de código que depende de la llamada Sort () porque esta clase en particular se heredó originalmente de la Lista y se cambió recientemente para que fuera una lista de Binding.
Así que específicamente, tengo una clase llamada VariableCode y una clase de colección llamada VariableCodeList. VariableCode implementa IComparable y la lógica allí es moderadamente compleja en función de varias propiedades, 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?
}
}
Hice algunos intentos fallidos para reutilizar el método ApplySortCore en Sort (), pero lo que me sigue frustrando es que ApplySortCore espera que un PropertyDescriptor haga su ordenamiento y no puedo encontrar la forma de usar IComparable .CompareTo () la lógica.
¿Alguien me puede apuntar en la dirección correcta?
Muchas gracias.
EDITAR: Este es el código final basado en la respuesta de Marc para referencia futura.
/// <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();
}
}
Emular una propiedad solo para hacer el ordenamiento es probablemente una exageración. Lo primero que debe mirar es Comparer<T>.Default
. Sin embargo, podría resultar que lo más fácil es:
- extraer los datos en la
List<T>
o similar - ordenar los datos extraídos
- Desactivar notificaciones
- recargar los datos
- volver a habilitar las notificaciones
- enviar un mensaje de "reinicio"
Por cierto, también debe desactivar las notificaciones durante su clasificación existente.
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();
}
}
Tuve el mismo problema y este post me ayudó a resolverlo.
Como implementé esta solución (basada en el código de Marc y Paul) como una extensión y agregué dos métodos de clasificación simples, me gustaría compartirla con ustedes:
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);
}
}
Espero que esto sea de ayuda.