![](/img/trans.png)
[英]How to sort DataGridView when bound to a binding source that is linked to an EF4 Entity
[英]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的一個片段和截圖到演示:
// 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集合進行排序 。 以下是關於此問題的許多有用參考的鏈接匯編:
如果你想要擴展方法.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.