Powiązanie List <T> do DataGridView w WinForm

91

mam klasę

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

i a List<Person>do którego dodaję kilka pozycji. Lista jest powiązana z my 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;

Nie ma problemu. myGridwyświetla dwa wiersze, ale kiedy dodaję nowe pozycje do mojej personslisty, myGridnie pokazuje nowej zaktualizowanej listy. Pokazuje tylko dwa wiersze, które dodałem wcześniej.

Więc jaki jest problem?

Rebindowanie za każdym razem działa dobrze. Ale kiedy wiążę a DataTablez siatką, kiedy za każdym razem, gdy wprowadzam jakieś zmiany, DataTablenie ma potrzeby ponownego wiązania myGrid.

Jak rozwiązać ten problem bez ponownego wiązania za każdym razem?

namco
źródło

Odpowiedzi:

188

Lista nie jest implementowana, IBindingListwięc siatka nie wie o twoich nowych przedmiotach.

BindingList<T>Zamiast tego powiąż DataGridView z plikiem.

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

Ale poszedłbym nawet dalej i związał twoją siatkę z 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
źródło
Mówi się, że możesz również używać IList i innych interfejsów: msdn.microsoft.com/en-us/library/…
Pacane
4
@Pacane: Jasne, że możesz, ale DataGridView musi wiedzieć, czy Twoje źródło danych ma jakieś zmiany. Onesposób polega na użyciu BindingList, który wywoła zdarzenie, jeśli zmieni się lista bazowa. Innym sposobem jest użycie BindingSourcei wywołanie ResetBinding () za każdym razem, gdy dodajesz / usuwasz wiersz, ale to o wiele więcej pracy. Jeśli chcesz poinformować Grid o zmianach właściwości, najłatwiej to wdrożyćINotifyPropertyChanged
Jürgen Steinblock
5
dlaczego użyłeś BindingList i BindingSource, ponieważ możemy bezpośrednio powiązać listę z właściwością źródła danych datagridview. omów znaczenie użytych tutaj BindingList i BindingSource. dzięki
Mou
5
@Mou Jeśli chcesz, możesz powiązać DataGrid z a List<T>. Ale jeśli programowo dodasz elementy do listy, DataGridView nie będzie o tym wiedział, ponieważ List nie zawiera implementu IBindingList. Odnośnie BindingSource: często używam winforms i nie wiążę się z niczym innym niż BindingSource - FULLSTOP. Dodanie większej ilości szczegółów to zbyt wiele, aby dodać komentarz, ale BindingSourcema tak wiele do zaoferowania bez żadnych wad. Anyone who does not use a BindingSource for binding has not fully understood windows forms databindings
Poszedłbym
4
@CraigBrett Traktuj BindingSourcejako pomost między źródłem danych a interfejsem użytkownika. Rozwiązuje wiele problemów związanych z wiązaniem danych. Chcesz ponownie załadować swoje dane? Po prostu ustaw bindingSource.DataSourcenową kolekcję zamiast ponownego wiązania każdej kontrolki. Twoje źródło danych może mieć wartość NULL? Zestaw bindingSource.DataSource = typeof(YourClass)Chcesz mieć edytowalną siatkę, ale Twoje źródło danych nie ma konstruktora bez parametrów? Po prostu zaimplementuj bindingSource.AddingNewzdarzenie i stwórz obiekt samodzielnie. Nigdy nie doświadczyłem minusów podczas używania, BindingSourceale wiele korzyści.
Jürgen Steinblock
4

Za każdym razem, gdy dodajesz nowy element do listy, musisz ponownie powiązać swoją siatkę. Coś jak:

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
źródło
Nie widzę właściwości dataSource pod datagrid. Czy możesz mi powiedzieć, jak z niej korzystać?
RSB
2

Tak, można to zrobić bez ponownego wiązania, implementując interfejs INotifyPropertyChanged.

Całkiem prosty przykład jest dostępny tutaj,

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

Dev
źródło
1
To nie wystarczy, jeśli zaimplementujesz INotifyPropertyChangedDataGridView, pokaże wszystkie zmiany właściwości, które mają miejsce w tle, ale nie będzie wiedział, czy dodasz / usuniesz wiersz ze źródła. Do tego celu służy IBindingListinterfejs i, dla Twojej wygody, BindingList<T>implementacja, która już go implementuje, ale nie obsługuje sortowania / filtrowania.
Jürgen Steinblock
1
Tak, zgodziłbym się z tobą. więc myślę, że do tego można użyć ObservableCollection <T>. Co myślisz?
Dev,
0

Po dodaniu nowej pozycji do personsdodania:

myGrid.DataSource = null;
myGrid.DataSource = persons;
Rafał
źródło
Nie widzę właściwości dataSource pod datagrid. Czy możesz mi powiedzieć, jak z niej korzystać?
RSB
1
Ta sugestia może powodować problemy. Na przykład może się okazać, że kliknięcie elementu w siatce może spowodować uzyskanie wyjątku IndexOutOfRangeException, ponieważ w tym momencie źródło danych ma wartość null. Rozsądniej byłoby początkowo powiązać się z BindingList i zaimplementować INotifyPropertyChanged na swoim obiekcie, jak wskazują inne odpowiedzi
steve
Jaki jest sens przypisywania go, nulljeśli od razu przypisujesz go do personsnastępnego wiersza?
Rufus L
0

To nie jest dokładnie ten problem, który miałem, ale jeśli ktoś chce przekonwertować BindingList dowolnego typu na Listę tego samego typu, to jest to jak to zrobić:

var list = bindingList.ToDynamicList();

Ponadto, jeśli przypisujesz BindingLists typów dynamicznych do DataGridView.DataSource, upewnij się, że najpierw zadeklarowałeś go jako IBindingList, aby powyższe działało.

Kopfs
źródło