如何对绑定到EF EntityCollection的WinForms DataGridView进行排序<t> </t>

时间:2011-05-05 19:38:06

标签: c# winforms entity-framework-4 datagridview entitycollection

我正在尝试将WinForms DataGridView绑定到EntityFramework4对象的EntityCollection<T>。麻烦的是,我无法弄清楚如何对其进行排序(自动)。

我正在做的就是将BindingSource的DataSource属性设置为实体的集合。

MyBindingSource.DataSource = CurrentItem.InvoiceNotes;

我真的希望我可以添加一个简单的配置来使其工作;我真的不想将我的EF Collection包装在一个新的BindingList容器中。

3 个答案:

答案 0 :(得分:3)

为了支持排序,源需要在启用排序的情况下实现IBindingList。令人讨厌的是,AFAIK唯一的内置类型是DataView

但是,一切都不会丢失;您最好的选择是创建BindingList<T>数据 - 或者更确切地说,是互联网上可用的许多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的更改(也在我以前的帖子中)
  •   

答案 1 :(得分:0)

添加到@ Marc-Gravell的答案,有a library that makes it easy to get sortable DGVs for any list,所以你可以使用它,只需在EF集合,IQueryables,IEnumerables等上调用.ToList()。现在的问题是,如果你使用.ToList()并排序,数据绑定仍然有效吗?在我的所有测试中,(令我惊讶的是)答案是(我在DGV和数据之间使用BindingSource

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

(编辑:将DGV直接绑定到BindingListView(BLV)似乎与使用DGV和BLV之间的BindingSource相同,因此您只需使用dgv.DataSource = efCollection并且仍然可以完全数据绑定。)

我花了很多时间研究这个问题并尝试理解why you can't just sort an EF collection out-of-the-box(或任何集合,就此而言)。以下是关于这个问题的许多有用参考资料的链接汇编:

一般数据绑定

一般的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

答案 2 :(得分:0)

谢谢Andrew Davey,his blog has many other interesting things.

这里在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)