c# - programmatic - datagridview1 sort
¿Cómo habilita la ordenación en un DataGridView con un DataSource asignado? (2)
En varias recomendaciones, comencé a asignar un DataSource
a mi DataGridView
lugar de usar DataGridView.Rows.Add(...)
. Esto es conveniente ya que mi fuente de datos ya es una gran lista que no cambia (mucho). Sin embargo, cuando uso la asignación de DataSource
, resulta imposible ordenar las columnas.
class MyGridView : DataGridView
{
private List<Person> m_personList;
private class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Person(string first, string last)
{
FirstName = first;
LastName = last;
}
}
public MyGridView()
{
/* ...initialise stuff... */
m_personList.Add(new Person("Kate", "Smith"));
m_personList.Add(new Person("Bill", "Davids"));
m_personList.Add(new Person("Ann", "Roth"));
this.DataSource = m_personList;
}
}
También traté de reemplazar List<Person>
por BindingList<Person>
y por BindingSource
, pero nada de eso parece importar. También intenté agregar un clasificador personalizado:
this.SortCompare += MyGridView_SortCompare;
private void MyGridView_SortCompare(object sender, EventArgs e)
{
/* ...Compare method...*/
}
pero ni siquiera se llama. ¿Hay alguna otra forma de habilitar la clasificación con un DataSource?
Nota: Tenga en cuenta que mi DataSource no es (necesariamente) una SQL, sino cualquier List
.
Necesita forzar su fuente de datos en una lista que admita la ordenación (IBindingList e IBindingListView), y luego funcionará de la caja. Hay muchos ejemplos en la web, este es el que he usado en el pasado:
// usage:
// var sortableList = new SortableList(m_personList);
// dgv.DataSource = m_sortableList;
/// <summary>
/// Suitable for binding to DataGridView when column sorting is required
/// </summary>
/// <typeparam name="T"></typeparam>
public class SortableList<T> : BindingList<T>, IBindingListView
{
private PropertyComparerCollection<T> sorts;
public SortableList()
{
}
public SortableList(IEnumerable<T> initialList)
{
foreach (T item in initialList)
{
this.Add(item);
}
}
public SortableList<T> ApplyFilter(Func<T, bool> func)
{
SortableList<T> newList = new SortableList<T>();
foreach (var item in this.Where(func))
{
newList.Add(item);
}
return newList;
}
protected override bool IsSortedCore
{
get { return this.sorts != null; }
}
protected override bool SupportsSortingCore
{
get { return true; }
}
protected override ListSortDirection SortDirectionCore
{
get
{
return this.sorts == null
? ListSortDirection.Ascending
: this.sorts.PrimaryDirection;
}
}
protected override PropertyDescriptor SortPropertyCore
{
get
{
return this.sorts == null ? null : this.sorts.PrimaryProperty;
}
}
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);
}
this.sorts = tmp;
}
finally
{
RaiseListChangedEvents = oldRaise;
ResetBindings();
}
}
public bool Exists(Predicate<T> func)
{
return new List<T>(this).Exists(func);
}
string IBindingListView.Filter
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
void IBindingListView.RemoveFilter()
{
throw new NotImplementedException();
}
ListSortDescriptionCollection IBindingListView.SortDescriptions
{
get { return (this.sorts == null ? null : this.sorts.Sorts); }
}
bool IBindingListView.SupportsAdvancedSorting
{
get { return true; }
}
bool IBindingListView.SupportsFiltering
{
get { return false; }
}
protected override void RemoveSortCore()
{
this.sorts = null;
}
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
ListSortDescription[] arr = { new ListSortDescription(prop, direction) };
ApplySort(new ListSortDescriptionCollection(arr));
}
}
public class PropertyComparerCollection<T> : IComparer<T>
{
private readonly PropertyComparer<T>[] comparers;
private readonly ListSortDescriptionCollection 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));
}
this.comparers = list.ToArray();
}
public ListSortDescriptionCollection Sorts
{
get { return this.sorts; }
}
public PropertyDescriptor PrimaryProperty
{
get
{
return this.comparers.Length == 0
? null
: this.comparers[0].Property;
}
}
public ListSortDirection PrimaryDirection
{
get
{
return this.comparers.Length == 0
? ListSortDirection.Ascending
: this.comparers[0].Descending
? ListSortDirection.Descending
: ListSortDirection.Ascending;
}
}
int IComparer<T>.Compare(T x, T y)
{
int result = 0;
foreach (PropertyComparer<T> t in this.comparers)
{
result = t.Compare(x, y);
if (result != 0)
{
break;
}
}
return result;
}
}
public class PropertyComparer<T> : IComparer<T>
{
private readonly bool descending;
private readonly PropertyDescriptor property;
public PropertyComparer(PropertyDescriptor property, bool descending)
{
if (property == null)
{
throw new ArgumentNullException("property");
}
this.descending = descending;
this.property = property;
}
public bool Descending
{
get { return this.descending; }
}
public PropertyDescriptor Property
{
get { return this.property; }
}
public int Compare(T x, T y)
{
int value = Comparer.Default.Compare(this.property.GetValue(x),
this.property.GetValue(y));
return this.descending ? -value : value;
}
}
Una alternativa es convertir su Lista en DataTable y luego vincular esa DataTable a DataGridView a través de BindingSource. De esta forma, DataGridView heredará las opciones de ordenamiento disponibles con DataTable.
Para convertir una lista en DataTable, consulte el artículo: Cómo llenar una tabla de datos con List <T>