Adding on to @Marc-Gravell's answer, there is a library that makes it easy to get sortable DGVs for any list, so you can use it and just call .ToList()
on EF collections, IQueryables, IEnumerables, etc. Now the question is, if you use .ToList()
and sort, will databinding still work? In all of my tests, the (surprising, to me) answer is yes (I use a BindingSource
between the DGV and the data).
Here's a snippet from LINQPad and a screenshot to demo:
// 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();
}
}
}
}
(EDIT: Binding the DGV directly to the BindingListView
(BLV) seems to work the same as using the BindingSource
between the DGV and the BLV, so you can just use dgv.DataSource = efCollection
and still get full databinding.)
I've spent a lot of time researching this question and trying to understand why you can't just sort an EF collection out-of-the-box (or any collection, for that matter). Here's a compilation of links to a lot of useful references regarding this question:
Data binding in general
DGV sorting and databinding in general
EF specific
Master/Detail (a.k.a. Parent/Child) views
And if you want the extension method .IsDirty()
, here it is in VB (needs to be in a Module with the correct Imports statements):
''' <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
EntityCollection<T>
inherit IListSource, or BindingList<T>? If not, then you should write an AutoSort routine called by the DataSource.Changed event. There are tons of sorting routines available on the Googlenet... :) – Tribulation