Как отсортировать WinForms DataGridView, привязанный к EF EntityCollection <T> - PullRequest
5 голосов
/ 05 мая 2011

Я пытаюсь привязать WinForms DataGridView к EntityCollection<T> из объекта EntityFramework4. Проблема в том, что я не могу понять, как заставить его сортировать (автоматически).

Все, что я делаю, это задаю для свойства BindingSource DataSource коллекцию сущности.

MyBindingSource.DataSource = CurrentItem.InvoiceNotes;

Я действительно надеюсь, что есть простая конфигурация, которую я могу добавить к этому, чтобы заставить ее работать; Я действительно не хочу оборачивать мою коллекцию EF в новый контейнер BindingList.

Ответы [ 3 ]

3 голосов
/ 05 мая 2011

Для поддержки сортировки в источнике должна быть реализована 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 скрыты (также в моем предыдущем посте)
0 голосов
/ 18 июля 2014

Спасибо, Эндрю Дейви, в его блоге есть много других интересных вещей.

Вот простое использование 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)
0 голосов
/ 30 июля 2013

В дополнение к ответу @ Marc-Gravell, есть библиотека, которая позволяет легко получать сортируемые DGV для любого списка , так что вы можете использовать его и просто вызывать .ToList() для коллекций EF, IQueryables , IEnumerables и т. Д. Теперь возникает вопрос: если вы используете .ToList() и sort, будет ли работать привязка данных? Во всех моих тестах (удивительно для меня) ответом является да (я использую BindingSource между DGV и данными).

Вот фрагмент из LINQPad и скриншот для демонстрации:

Sortable data from EF collection. Sorted descending on scan column.

// 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();
            }
        }
    }
}

(EDIT: привязка DGV напрямую к BindingListView (BLV), похоже, работает так же, как и использование BindingSource между DGV и BLV, поэтому вы можете просто использовать dgv.DataSource = efCollection и при этом получить полную привязку данных. )

Я потратил много времени на изучение этого вопроса и попытался понять , почему вы не можете просто отсортировать коллекцию EF из коробки (или любую коллекцию, если на то пошло) , Вот подборка ссылок на множество полезных ссылок по этому вопросу:

Привязка данных в целом

DGV сортировка и привязка данных в целом

EF специфично

Основные / подробные (a.k.a. Родитель / Ребенок) просмотров

А если вам нужен метод расширения .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
...