Как отсортировать WinForms DataGridView, привязанный к EF EntityCollection<T>
Я пытаюсь привязать WinForms DataGridView к EntityCollection<T>
из объекта EntityFramework4. Проблема в том, что я не могу понять, как заставить его сортировать (автоматически).
Все, что я делаю, это устанавливаю свойство DataSource объекта BindingSource в коллекцию объекта.
MyBindingSource.DataSource = CurrentItem.InvoiceNotes;
Я действительно надеюсь, что есть простая конфигурация, которую я могу добавить к этому, чтобы заставить ее работать; Я действительно не хочу оборачивать мою коллекцию EF в новый контейнер BindingList.
3 ответа
Для поддержки сортировки источник должен реализовать IBindingList
с включенной сортировкой. Досадно, AFAIK единственный встроенный тип с этим DataView
,
Однако еще не все потеряно; ваш лучший вариант - создать BindingList<T>
ваших данных - или, скорее, один из многих BindingList<T>
Подклассы доступны в качестве примеров в Интернете. BindingList<T>
это дает вам 90% пути - ему нужно всего лишь 3 (IIRC) дополнительных метода реализации, чтобы получить базовую (одностолбцовую) поддержку сортировки.
Динеш Чанднани написал серию статей еще в 2005 году ( http://blogs.msdn.com/b/dchandnani/archive/2005/03.aspx), которые хорошо объясняют привязку через BindingSource. Он был написан до EF, но он предоставляет хорошую справочную информацию. Вот один лакомый кусочек:
Конечно, вы можете привязать DataGridView к DataTable напрямую и обойти BindingSource, но BindingSource имеет определенные преимущества:
- Он предоставляет свойства для сортировки списка, фильтрации списка и т. Д., Что в противном случае было бы непросто. (т.е. если вы связываете DataGridView с DataTable напрямую, то для сортировки DataTable вам нужно знать, что DataTable - это IListSource, который знает базовый список, который является DataView, и DataView можно сортировать, фильтровать и т. д.).
- Если вам нужно настроить основные / дочерние представления, то BindingSource отлично справится с этим (подробнее в моем предыдущем посте)
- Изменения в DataTable скрыты (также в моем предыдущем посте)
В дополнение к ответу @Marc-Gravell, есть библиотека, которая позволяет легко получать сортируемые DGV для любого списка, так что вы можете использовать его и просто вызвать .ToList()
на коллекциях EF, IQueryables, IEnumerables и т. д. Теперь возникает вопрос, если вы используете .ToList()
и сортировка, будет ли работать привязка данных? Во всех моих тестах (удивительно для меня) ответ - да (я использую BindingSource
между DGV и данными).
Вот фрагмент из LINQPad и скриншот для демонстрации:
// http://www.csharpbydesign.com/2009/07/linqbugging---using-linqpad-for-winforms-testing.html
void Main()
{
var context = this;
using (var form = new Form())
{
var dgv = new DataGridView();
var binder = new BindingSource();
// All of the following variations work
// var efCollection = context.NOS_MDT_PROJECT;
// var sortableCollection = new BindingListView<NOS_MDT_PROJECT>(
// efCollection.ToList());
// var efCollection = context.NOS_MDT_PROJECT.First()
// .NOS_DEFL_TEST_SECT;
// var sortableCollection = new BindingListView<NOS_DEFL_TEST_SECT>(
// efCollection.ToList());
var efCollection =
from p in context.NOS_MDT_PROJECT
where p.NMP_ID==365
from s in p.NOS_GPR_TST_SECT_COMN_DATA
from l in s.NOS_GPR_TST_LOC_DATA
select l;
var sortableCollection = new BindingListView<NOS_GPR_TST_LOC_DATA>(
efCollection.ToList());
binder.DataSource = sortableCollection;
dgv.DataSource = binder;
dgv.Dock = DockStyle.Fill;
form.Controls.Add(dgv);
form.Shown += (o, e) => {
dgv.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
};
form.ShowInTaskbar=true;
form.ShowDialog();
if (context.IsDirty()) // Extension method
{
if (DialogResult.Yes == MessageBox.Show("Save changes?", "",
MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2))
{
context.SaveChanges();
}
}
}
}
(РЕДАКТИРОВАТЬ: привязка DGV непосредственно к BindingListView
(BLV), кажется, работает так же, как использование BindingSource
между DGV и BLV, так что вы можете просто использовать dgv.DataSource = efCollection
и до сих пор получить полную привязку данных.)
Я потратил много времени на изучение этого вопроса и пытался понять, почему нельзя просто отсортировать коллекцию EF "из коробки" (или любую другую коллекцию). Вот подборка ссылок на множество полезных ссылок по этому вопросу:
Привязка данных в целом
- За кулисами: улучшения в привязке данных Windows Forms в.NET Framework 2.0, часть 2
- Подробное руководство по привязке данных - CodeProject
DGV сортировка и привязка данных в целом
- Сортировка DataGridView с использованием пользовательского BindingList ← КОДЕКС
- Как реализовать автоматическую сортировку DataGridView? - Переполнение стека
- Как отсортировать DataGridView, который связан с коллекцией пользовательских объектов? - Переполнение стека
- Реализация сортируемого BindingList очень, очень быстро - CodeProject
EF определенный
- Советы по привязке данных Entity Framework - Diego Vega - Сайт сайта - Блоги MSDN
- Показать результаты LINQ to Entities в DataGridViews и возможность сортировки
- Использование коллекции WPF ObservableCollection с объектами EF - Бет Масси - Делимся добротой - Главная страница сайта - Блоги MSDN
Master/Detail (он же родитель / ребенок) просмотров
- Привязка данных Master-Detail в WPF с Entity Framework - Бет Масси - Делимся добром - Сайт Главная - Блоги MSDN
- Сортировка включенной коллекции, привязанной к списку
И если вы хотите метод расширения .IsDirty()
здесь он находится в VB (должен быть в модуле с правильными утверждениями Imports):
''' <summary>
''' Determines whether the specified object context has changes from original DB values.
''' </summary>
''' <param name="objectContext">The object context.</param>
''' <returns>
''' <c>true</c> if the specified object context is dirty; otherwise, <c>false</c>.
''' </returns>
<System.Runtime.CompilerServices.Extension()> _
Public Function IsDirty(ByVal objectContext As ObjectContext) As Boolean
Return objectContext.ObjectStateManager.GetObjectStateEntries(
EntityState.Added Or EntityState.Deleted Or EntityState.Modified).Any()
End Function
Спасибо Эндрю Дэйви, в его блоге есть много других интересных вещей.
Вот простое использование BindingListView (BLV) в Vb.net, которое тоже работает:
Imports Equin.ApplicationFramework
Dim elements As List(Of projectDAL.Document) = db.Document.Where(
Function(w)w.IdProject = _activeProject.Id).OrderBy(Function(i) i.Description).ToList
Dim mySource As BindingListView(Of projectDAL.Document)
mySource = New BindingListView(Of projectDAL.Document)(elements)