Comment sortinger WinForms DataGridView lié à EF EntityCollection

J’essaie de lier un WinForms DataGridView à un EntityCollection partir d’un object EntityFramework4. Le problème, c’est que je ne vois pas comment le faire sortinger (automatiquement).

Je ne fais que définir la propriété DataSource de BindingSource sur la collection de l’entité.

MyBindingSource.DataSource = CurrentItem.InvoiceNotes;

J’espère vraiment qu’il y a une configuration simple à append pour que cela fonctionne; Je ne veux vraiment pas avoir à emballer ma collection EF dans un nouveau conteneur BindingList.

Pour prendre en charge le sorting, la source doit implémenter IBindingList avec le sorting activé. Ce qui est ennuyeux, c’est que DataView est le seul type intégré à cela.

Cependant tout n’est pas perdu; Votre meilleure option est de créer une BindingList de vos données – ou plutôt l’une des nombreuses sous-classes BindingList disponibles à titre d’exemple sur Internet. BindingList vous BindingList 90% du chemin. Il suffit d’environ 3 méthodes supplémentaires (IIRC) à implémenter pour obtenir une prise en charge de base du sorting (une colonne).

Dinesh Chandnani a écrit une série d’articles en 2005 ( http://blogs.msdn.com/b/dchandnani/archive/2005/03.aspx ) qui expliquent bien la liaison via BindingSource. Il a été écrit avant EF, mais il fournit de bonnes informations de base. Voici une friandise:

Bien sûr, vous pouvez lier directement DataGridView à DataTable et contourner BindingSource, mais BindingSource présente certains avantages:

  • Il expose les propriétés pour sortinger la liste, filtrer la liste, etc., ce qui serait autrement difficile à faire. (Par exemple, si vous liez le DataGridView au DataTable directement, pour sortinger le DataTable, vous devez savoir que DataTable est un IListSource qui connaît la liste sous-jacente qui est un DataView et un DataView peut être sortingé, filtré, etc.).
  • Si vous devez configurer des vues maître / enfant, BindingSource fait un excellent travail en ce sens (plus de détails dans mon précédent post)
  • Les modifications apscopes au DataTable sont masquées (également dans mon précédent post)

En plus de la réponse de @ Marc-Gravell, il existe une bibliothèque qui facilite l’obtention de fichiers DGV sortingables pour toute liste . Vous pouvez donc l’utiliser et appeler simplement .ToList() sur des collections EF, IQueryables, IEnumerables, etc. Maintenant, la question Si vous utilisez .ToList() et que vous sortingez, la liaison de données fonctionnera-t-elle encore? Dans tous mes tests, la réponse (surprenante, pour moi) est oui (j’utilise un BindingSource entre le DGV et les données).

Voici un extrait de LINQPad et une capture d’écran pour une démonstration:

Données triables de la collection EF. Tri décroissant dans la colonne d'analyse.

 // 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( // efCollection.ToList()); // var efCollection = context.NOS_MDT_PROJECT.First() // .NOS_DEFL_TEST_SECT; // var sortableCollection = new BindingListView( // 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( 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: La liaison du BindingListView DGV directement à BindingListView (BLV) semble fonctionner de la même manière que l’utilisation du BindingSource entre le BindingSource DGV et le BindingSource BLV. Vous pouvez donc simplement utiliser dgv.DataSource = efCollection et obtenir une dgv.DataSource = efCollection complète.)

J’ai passé beaucoup de temps à étudier cette question et à essayer de comprendre pourquoi vous ne pouvez pas simplement sortinger une collection EF prête à l’emploi (ou toute collection, d’ailleurs). Voici une compilation de liens vers de nombreuses références utiles concernant cette question:

Liaison de données en général

  • Dans les coulisses: améliorations de la liaison de données Windows Forms dans le .NET Framework 2.0, partie 2
  • Didacticiel de liaison de données détaillé – CodeProject

Tri DGV et databinding en général

  • DataGridView Sorting Using Custom BindingList ← CODEcisions
  • c # – Comment implémenter le sorting automatique de DataGridView? – débordement de stack
  • c # – Comment sortinger un DataGridView lié à une collection d’objects personnalisés? – débordement de stack
  • Implémentation d’une liste de liaison sortingable très, très rapidement – CodeProject

EF spécifique

  • Conseils rapides pour la liaison de données Entity Framework – Diego Vega – Accueil – MSDN Blogs
  • Afficher les résultats LINQ to Entities dans DataGridViews et pouvoir sortinger
  • Utilisation de WPF ObservableCollection avec des entités EF – Beth Massi – Partager le bien – Accueil du site – MSDN Blogs

Vues maître / détail (parent / enfant)

  • Liaison de données maître-détail dans WPF avec Entity Framework – Beth Massi – Partager le bien – Accueil du site – MSDN Blogs
  • Tri d’une collection incluse liée à une liste

Et si vous voulez la méthode d’extension .IsDirty() , la voici en VB (doit être dans un module avec les instructions Imports correctes):

 '''  ''' Determines whether the specified object context has changes from original DB values. '''  ''' The object context. '''  ''' true if the specified object context is dirty; otherwise, false. '''   _ Public Function IsDirty(ByVal objectContext As ObjectContext) As Boolean Return objectContext.ObjectStateManager.GetObjectStateEnsortinges( EntityState.Added Or EntityState.Deleted Or EntityState.Modified).Any() End Function 

Merci Andrew Davey, son blog a beaucoup d’autres choses intéressantes.

Voici une utilisation simple de BindingListView (BLV) dans Vb.net qui fonctionne aussi:

 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)