Сортировка DataGridView и, например, BindingList in.NET
Я использую BindingList<T>
в моих Windows Forms, который содержит список"IComparable<Contact>
" контакт-объекты. Теперь я хотел бы, чтобы пользователь мог Сортировать по любому столбцу, отображаемому в сетке.
существует способ, описанный в MSDN online, который показывает, как реализовать пользовательскую коллекцию на основе BindingList<T>
, которая позволяет сортировать. Но нет ли Sort-event или чего-то, что может быть поймано в DataGridView (или, еще лучше, на BindingSource) для сортировки базовой коллекции с помощью custom код?
мне не очень нравится способ, описанный в MSDN. С другой стороны, я мог бы легко применить запрос LINQ к коллекции.
6 ответов
Я очень ценю Маттиас' для своей простоты и красоты.
, а это дает отличные результаты для низких объемов данных, при работе с большими объемами данных производительность не так хорошо, из-за отражения.Я провел тест с коллекцией простых объектов данных, насчитывающих 100000 элементов. Сортировка по свойству целочисленного типа заняла около 1 мин. Реализации я собираюсь более подробно следует ~200мс.
основная идея заключается в пользу строгой типизацией сравнения, сохраняя при этом способ ApplySortCore универсальный. Следующее заменяет универсальный делегат сравнения вызовом конкретного компаратора, реализованного в производном классе:
новое в SortableBindingList
protected abstract Comparison<T> GetComparer(PropertyDescriptor prop);
ApplySortCore изменения в:
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
List<T> itemsList = (List<T>)this.Items;
if (prop.PropertyType.GetInterface("IComparable") != null)
{
Comparison<T> comparer = GetComparer(prop);
itemsList.Sort(comparer);
if (direction == ListSortDirection.Descending)
{
itemsList.Reverse();
}
}
isSortedValue = true;
sortPropertyValue = prop;
sortDirectionValue = direction;
}
Теперь в производном классе нужно реализовать компараторы для каждого сортируемого свойства:
class MyBindingList:SortableBindingList<DataObject>
{
protected override Comparison<DataObject> GetComparer(PropertyDescriptor prop)
{
Comparison<DataObject> comparer;
switch (prop.Name)
{
case "MyIntProperty":
comparer = new Comparison<DataObject>(delegate(DataObject x, DataObject y)
{
if (x != null)
if (y != null)
return (x.MyIntProperty.CompareTo(y.MyIntProperty));
else
return 1;
else if (y != null)
return -1;
else
return 0;
});
break;
// Implement comparers for other sortable properties here.
}
return comparer;
}
}
}
этот вариант требует немного больше кода, но, если производительность является проблемой, я думаю, что это стоит усилий.
я погуглил и попробовал еще раз...
в .NET пока нет встроенного способа. Вы должны реализовать пользовательский класс на основе BindingList<T>
. Один из способов описан в привязка пользовательских данных, Часть 2 (MSDN). Я, наконец, производит другую реализацию ApplySortCore
- метод для обеспечения реализации, которая не зависит от проекта.
protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
{
List<T> itemsList = (List<T>)this.Items;
if(property.PropertyType.GetInterface("IComparable") != null)
{
itemsList.Sort(new Comparison<T>(delegate(T x, T y)
{
// Compare x to y if x is not null. If x is, but y isn't, we compare y
// to x and reverse the result. If both are null, they're equal.
if(property.GetValue(x) != null)
return ((IComparable)property.GetValue(x)).CompareTo(property.GetValue(y)) * (direction == ListSortDirection.Descending ? -1 : 1);
else if(property.GetValue(y) != null)
return ((IComparable)property.GetValue(y)).CompareTo(property.GetValue(x)) * (direction == ListSortDirection.Descending ? 1 : -1);
else
return 0;
}));
}
isSorted = true;
sortProperty = property;
sortDirection = direction;
}
используя этот, вы можете сортировать по любому члену, который реализует IComparable
.
Я понимаю, что все эти ответы были хороши в то время, когда они были написаны. Возможно, так оно и есть. Я искал что-то похожее и нашел альтернативное решение для преобразования любой список или коллекция для сортировки BindingList<T>
.
вот важный фрагмент (ссылка на полный образец приведена ниже):
void Main()
{
DataGridView dgv = new DataGridView();
dgv.DataSource = new ObservableCollection<Person>(Person.GetAll()).ToBindingList();
}
это решение использует метод расширения существующих в Entity Framework библиотека. Поэтому, пожалуйста, рассмотрите следующее прежде чем продолжить:
- если вы не хотите использовать Entity Framework, это нормально, это решение также не использует его. Мы просто используем метод расширения, который они разработали. Размер EntityFramework.dll составляет 5 Мб. Если он слишком велик для вас в эпоху петабайт, не стесняйтесь извлекать метод и его зависимости из приведенной выше ссылки.
- если вы используете (или хотите использовать) Entity Framework (>=v6.0), вам не о чем беспокоиться. Просто установите Entity Framework NuGet-пакет и вперед.
Я загрузил помощью linqpad пример кода здесь.
- загрузите образец, откройте его с помощью LINQPad и нажмите F4.
- вы должны увидеть EntityFramework.dll в красном цвете. Загрузите dll из этого расположение. Просмотрите и добавьте ссылку.
- нажмите OK. Нажмите Клавишу F5.
Как вы можете видеть, вы можете сортировка по всем четырем столбцам различных типов данных, щелкнув их заголовки столбцов в элементе управления DataGridView.
те, у кого нет LINQPad, все еще могут загрузить запрос и открыть его с помощью блокнота, чтобы увидеть полный образец.
вот альтернатива, которая очень чистая и отлично работает в моем случае. У меня уже были определенные функции сравнения, настроенные для использования со списком.Сортировка (сравнение), поэтому я просто адаптировал это из частей других примеров StackOverflow.
class SortableBindingList<T> : BindingList<T>
{
public SortableBindingList(IList<T> list) : base(list) { }
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)
{
if(typeof(T).GetInterface(typeof(IComparable).Name) != null)
{
bool originalValue = this.RaiseListChangedEvents;
this.RaiseListChangedEvents = false;
try
{
List<T> items = (List<T>)this.Items;
if(p_Comparison != null) items.Sort(p_Comparison);
else items.Sort(p_Comparer);
}
finally
{
this.RaiseListChangedEvents = originalValue;
}
}
}
}
вот это новое реализовать, используя несколько новых трюков.
базовый тип IList<T>
необходимо реализовать void Sort(Comparison<T>)
или вы должны передать делегат, чтобы вызвать функцию сортировки для вас. (IList<T>
нет
Не для пользовательских объектов. В .Net 2.0 мне пришлось свернуть сортировку с помощью BindingList. В .Net 3.5 может быть что-то новое, но я еще не изучил это. Теперь, когда есть LINQ и параметры сортировки, которые поставляются, если это теперь может быть проще реализовать.