C# 如何对绑定到EF EntityCollection的WinForms DataGridView排序<;T>;

C# 如何对绑定到EF EntityCollection的WinForms DataGridView排序<;T>;,c#,winforms,entity-framework-4,datagridview,entitycollection,C#,Winforms,Entity Framework 4,Datagridview,Entitycollection,我正在尝试从EntityFramework4对象将WinForms DataGridView绑定到EntityCollection。问题是,我不知道如何(自动)排序 我所做的只是将BindingSource的DataSource属性设置为实体的集合 MyBindingSource.DataSource=CurrentItem.InvoiceNotes 我真的希望有一个简单的配置,我可以添加到这个工作;我真的不想将我的EF集合包装在一个新的BindingList容器中。要支持排序,源代码需要在启用

我正在尝试从EntityFramework4对象将WinForms DataGridView绑定到
EntityCollection
。问题是,我不知道如何(自动)排序

我所做的只是将BindingSource的DataSource属性设置为实体的集合

MyBindingSource.DataSource=CurrentItem.InvoiceNotes


我真的希望有一个简单的配置,我可以添加到这个工作;我真的不想将我的EF集合包装在一个新的BindingList容器中。

要支持排序,源代码需要在启用排序的情况下实现
IBindingList
。令人烦恼的是,AFAIK唯一的内置类型是
DataView

然而,一切都没有失去;您最好的选择是创建数据的
BindingList
,或者更确切地说,是internet上可用的众多
BindingList
子类之一
BindingList
提供了90%的排序支持—它只需要实现3个(IIRC)附加方法即可获得基本(一列)排序支持

Dinesh Chandnani在2005年()写了一系列文章,通过BindingSource很好地解释了绑定。它是在EF之前写的,但它提供了一些很好的背景信息。这里有一个小道消息:

当然,您可以将DataGridView直接绑定到DataTable并 绕过BindingSource,但BindingSource具有某些优势:

  • 它公开属性来对列表进行排序、过滤列表等,这在其他方面是一件很痛苦的事情。(即,如果您将 DataGridView直接访问DataTable,然后对所需的DataTable进行排序 需要知道DataTable是一个IListSource,它知道 作为DataView和DataView的基础列表可以排序, 过滤等)
  • 如果您必须设置主/子视图,那么BindingSource在这方面做得很好(更多详细信息请参阅我之前的文章)
  • 对DataTable的更改是隐藏的(也在我上一篇文章中)

除了@Marc Gravell的答案之外,还有,所以你可以使用它,只需对EF集合、IQueryables、IEnumerables等调用
.ToList()
。现在的问题是,如果你使用
.ToList()
和排序,数据绑定还能工作吗?在我所有的测试中,(令我惊讶的是)答案是(我在DGV和数据之间使用
BindingSource

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

谢谢安德鲁·戴维

下面是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)

EntityCollection
继承IListSource还是BindingList?如果没有,则应该编写DataSource.Changed事件调用的自动排序例程。Googlenet上提供了大量排序例程…:)它确实支持IListSource,但不支持BindingList。既然它实现了IListSource,我能做些什么来启用排序吗?真是令人烦恼。我已经有了一个BindingList实现,但是这个网格应该支持添加和删除项,所以我想直接访问EntityCollection。哦,我只需要向EntityCollection和BindingList添加新项;我不得不做更糟糕的事情。我通常创建一个通过公共getter访问的内部绑定列表。注意:我通常不使用可编辑的数据网格。
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)