我正在尝试将WinForms DataGridView绑定到EntityFramework4对象的EntityCollection<T>
。麻烦的是,我无法弄清楚如何对其进行排序(自动)。
我正在做的就是将BindingSource的DataSource属性设置为实体的集合。
MyBindingSource.DataSource = CurrentItem.InvoiceNotes;
我真的希望我可以添加一个简单的配置来使其工作;我真的不想将我的EF Collection包装在一个新的BindingList容器中。
答案 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的一个片段和演示截图:
// 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(或任何集合,就此而言)。以下是关于这个问题的许多有用参考资料的链接汇编:
如果你想要扩展方法.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)