5

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

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

MyBindingSource.DataSource = CurrentItem.InvoiceNotes;

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

4

3 回答 3

3

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

不过,一切都没有丢失;您最好的选择是创建您的数据 - 或者更确切地说,是互联网上作为示例可用BindingList<T>的众多子类之一。让您完成 90% 的工作 - 它只需要实施大约 3 个(IIRC)附加方法即可获得基本(单列)排序支持。BindingList<T>BindingList<T>

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 的更改被隐藏(也在我之前的帖子中)
于 2011-05-05T19:59:37.963 回答
1

除了@Marc-Gravell 的回答之外,还有一个库可以轻松获取任何列表的可排序 DGV,因此您可以使用它并调用.ToList()EF 集合、IQueryables、IEnumerables 等。现在的问题是,如果您使用.ToList()和排序,数据绑定仍然有效吗?在我所有的测试中,(令我惊讶的是)答案是肯定的(我BindingSource在 DGV 和数据之间使用 a)。

这是来自 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)似乎与BindingSource在 DGV 和 BLV 之间使用相同,因此您可以使用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
于 2013-07-30T16:32:59.437 回答
0

谢谢 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)
于 2014-07-18T13:58:32.870 回答