簡體   English   中英

如何對綁定到EF EntityCollection的WinForms DataGridView進行排序<T>

[英]How to Sort WinForms DataGridView bound to EF EntityCollection<T>

我正在嘗試從EntityFramework4對象將WinForms DataGridView綁定到EntityCollection<T> 麻煩的是,我無法弄清楚如何對其進行排序(自動)。

我所做的就是將BindingSource的DataSource屬性設置為實體的集合。

MyBindingSource.DataSource = CurrentItem.InvoiceNotes;

我真的希望有一個簡單的配置,我可以添加到它,以使其工作; 我真的不想將我的EF Collection包裝在一個新的BindingList容器中。

為了支持排序,源需要實現IBindingList並啟用排序。 令人討厭的是,AFAIK唯一的內置類型就是DataView

但是,一切都不會丟失; 您最好的選擇是創建數據的BindingList<T> - 或者更確切地說,是Internet上可用的許多BindingList<T>子類之一。 BindingList<T>可以獲得90%的方式 - 它只需要大約3(IIRC)個附加方法來實現基本(單列)排序支持。

Dinesh Chandnani在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 ,所以你可以使用它,只需在EF集合,IQueryables,IEnumerables等上調用.ToList() 。現在問題是,如果你使用.ToList()和排序,數據綁定仍然有效嗎? 在我的所有測試中,(令我驚訝的是)答案是肯定的 (我在DGV和數據之間使用BindingSource )。

這是LINQPad的一個片段和截圖到演示:

來自EF集合的可排序數據。在掃描列上降序排序。

// 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)似乎與使用DGV和BLV之間的BindingSource相同,因此您只需使用dgv.DataSource = efCollection並仍然可以獲得完整的數據綁定。)

我花了很多時間研究這個問題並試圖理解為什么你不能只是開箱即用 (或任何集合)對EF集合進行排序 以下是關於此問題的許多有用參考的鏈接匯編:

數據綁定一般

DGV分類和數據綁定一般

EF具體

主/細節(又名父/子)視圖

如果你想要擴展方法.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

謝謝Andrew Davey, 他的博客還有很多有趣的東西。

這里在Vb.net中使用BindingListView(BLV)也很簡單:

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM