Liste de liaison <T> à DataGridView dans WinForm

91

j'ai un cours

class Person{
      public string Name {get; set;}
      public string Surname {get; set;}
}

et un List<Person>auquel j'ajoute quelques éléments. La liste est liée à mon DataGridView.

List<Person> persons = new List<Person>();
persons.Add(new Person(){Name="Joe", Surname="Black"});
persons.Add(new Person(){Name="Misha", Surname="Kozlov"});
myGrid.DataSource = persons;

Il n'y a pas de problème. myGridaffiche deux lignes, mais lorsque j'ajoute de nouveaux éléments à ma personsliste, myGridn'affiche pas la nouvelle liste mise à jour. Il ne montre que les deux lignes que j'ai ajoutées auparavant.

Alors quel est le problème?

La reliure à chaque fois fonctionne bien. Mais lorsque je lie un DataTableà la grille, à chaque fois que DataTablej'apporte des modifications, il n'est pas nécessaire de relier myGrid.

Comment le résoudre sans relier à chaque fois?

Namco
la source

Réponses:

187

La liste n'est pas implémentée, IBindingListdonc la grille ne connaît pas vos nouveaux éléments.

Liez votre DataGridView à un BindingList<T>.

var list = new BindingList<Person>(persons);
myGrid.DataSource = list;

Mais j'irais même plus loin et lierais ta grille à un BindingSource

var list = new List<Person>()
{
    new Person { Name = "Joe", },
    new Person { Name = "Misha", },
};
var bindingList = new BindingList<Person>(list);
var source = new BindingSource(bindingList, null);
grid.DataSource = source;
Jürgen Steinblock
la source
Il dit que vous pouvez également utiliser IList et d'autres interfaces: msdn.microsoft.com/en-us/library
...
4
@Pacane: Bien sûr que vous pouvez, mais le DataGridView a besoin de savoir si votre source de données a des changements. OneLa manière est d'utiliser une BindingList, qui déclenchera un événement si la liste sous-jacente change. Une autre façon consiste à utiliser un BindingSourceet à appeler ResetBinding () chaque fois que vous ajoutez / supprimez une ligne, mais c'est beaucoup plus de travail. Si vous souhaitez informer la grille des modifications de propriété, le moyen le plus simple est de mettre en œuvreINotifyPropertyChanged
Jürgen Steinblock
5
pourquoi avez-vous utilisé BindingList et BindingSource parce que nous pouvons directement lier la liste à la propriété datagridview datasource. discuter de l'importance de BindingList et BindingSource u utilisé ici. merci
Mou
5
@Mou Vous pouvez lier un DataGrid à un List<T>si vous le souhaitez. Mais si vous ajoutez des éléments par programme à la liste, DataGridView ne le saura pas car vous n'implémentez pas la liste IBindingList. Concernant BindingSource: J'utilise beaucoup winforms, et je ne me lie à rien d'autre qu'un BindingSource - FULLSTOP. Ajouter plus de détails est trop pour un commentaire, mais BindingSourcea tellement à offrir sans aucun inconvénient. Anyone who does not use a BindingSource for binding has not fully understood windows forms databindings
J'irais
4
@CraigBrett Considéré BindingSourcecomme un pont entre votre source de données et votre interface graphique. Il résout de nombreux problèmes liés à la liaison de données. Vous souhaitez recharger vos données? Définissez simplement bindingSource.DataSourcevotre nouvelle collection au lieu de relier chaque contrôle. Votre DataSource peut être nul? Set bindingSource.DataSource = typeof(YourClass)Vous souhaitez avoir une grille modifiable mais votre source de données n'a pas de constructeur sans paramètre? Implémentez simplement l' bindingSource.AddingNewévénement et créez vous-même l'objet. Je n'ai jamais ressenti d'inconvénient lors de l'utilisation, BindingSourcemais de nombreux avantages.
Jürgen Steinblock
4

Chaque fois que vous ajoutez un nouvel élément à la liste, vous devez relier à nouveau votre grille. Quelque chose comme:

List<Person> persons = new List<Person>();
persons.Add(new Person() { Name = "Joe", Surname = "Black" });
persons.Add(new Person() { Name = "Misha", Surname = "Kozlov" });
dataGridView1.DataSource = persons;

// added a new item
persons.Add(new Person() { Name = "John", Surname = "Doe" });
// bind to the updated source
dataGridView1.DataSource = persons;
Dimitar Dimitrov
la source
Je ne vois pas la propriété dataSource sous datagrid, pouvez-vous me dire comment l'utiliser?
RSB
2

Oui, il est possible de faire sans rebinding en implémentant l'interface INotifyPropertyChanged.

Un exemple assez simple est disponible ici,

http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx

Dev
la source
1
Ce n'est pas suffisant, si vous implémentez INotifyPropertyChangedle DataGridView affichera toutes les modifications de propriété qui se produisent en arrière-plan, mais il ne saura pas si vous ajoutez / supprimez une ligne de votre source. Pour cela, il existe une IBindingListinterface et, pour votre commodité, une implémentation BindingList<T>qui l'implémente déjà, mais ne prend pas en charge le tri / filtrage.
Jürgen Steinblock
1
Oui, je suis d’accord avec vous. donc je pense que ObservableCollection <T> peut être utilisé pour cela. Qu'est-ce que tu penses?
Dev
0

Après avoir ajouté un nouvel élément à personsajouter:

myGrid.DataSource = null;
myGrid.DataSource = persons;
Rafal
la source
Je ne vois pas la propriété dataSource sous datagrid, pouvez-vous me dire comment l'utiliser?
RSB
1
Cette suggestion pourrait causer des problèmes. Par exemple, vous pourriez trouver qu'un clic sur un élément dans la grille pourrait obtenir une IndexOutOfRangeException car la source de données est nulle à ce stade. Il serait plus sage de se lier à une BindingList initialement et d'implémenter INotifyPropertyChanged sur votre objet comme l'indiquent d'autres réponses
Steve
À quoi sert de l'attribuer nullsi vous l'attribuez immédiatement à personsla ligne suivante?
Rufus L le
0

Ce n'est pas exactement le problème que j'ai eu, mais si quelqu'un cherche à convertir une BindingList de n'importe quel type en List du même type, voici comment procéder:

var list = bindingList.ToDynamicList();

De plus, si vous affectez des BindingLists de types dynamiques à un DataGridView.DataSource, assurez-vous de le déclarer d'abord comme IBindingList afin que ce qui précède fonctionne.

Kopfs
la source