Привязка List <T> к DataGridView в WinForm


91

У меня есть класс

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

и, List<Person>к которому я добавляю некоторые элементы. Список привязан к моему 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;

Нет проблем. myGridотображает две строки, но когда я добавляю новые элементы в свой personsсписок, myGridновый обновленный список не отображается. Он показывает только две строки, которые я добавил ранее.

Так в чем проблема?

Переплет каждый раз работает хорошо. Но когда я привязываю DataTableк сетке, когда каждый раз, когда я DataTableвношу какие- то изменения , нет необходимости в повторной привязке myGrid.

Как решить без перепривязки каждый раз?

Ответы:


188

Список не реализуется, IBindingListпоэтому сетка не знает о ваших новинках.

BindingList<T>Вместо этого привяжите свой DataGridView к .

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

Но я бы даже пошел дальше и привязал вашу сетку к 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;

В нем говорится, что вы также можете использовать IList и другие интерфейсы: msdn.microsoft.com/en-us/library/…
Pacane

4
@Pacane: Конечно, можете, но DataGridView должен знать, есть ли в вашем источнике данных какие-либо изменения. Oneспособ использовать BindingList, который вызовет событие, если базовый список изменится. Другой способ - использовать BindingSourceи вызывать ResetBinding () каждый раз, когда вы добавляете / удаляете строку, но это намного больше работы. Если вы хотите информировать Grid об изменениях свойств, самый простой способ - это реализоватьINotifyPropertyChanged
Юрген Штайнблок,

5
Почему вы использовали BindingList и BindingSource, потому что мы можем напрямую привязать список к свойству источника данных datagridview. обсудите важность используемых здесь BindingList и BindingSource u. спасибо
Mou

5
@Mou Вы можете привязать DataGrid к a, List<T>если хотите. Но если вы программно добавляете элементы в список, DataGridView не будет знать об этом, потому что список не реализует IBindingList. Что касается BindingSource: я много использую winforms и не привязываюсь ни к чему другому, кроме BindingSource - FULLSTOP. Добавлять больше деталей - это слишком сложно для комментария, но BindingSourceесть что предложить без каких-либо недостатков. Я бы пошел так далеко и сказалAnyone who does not use a BindingSource for binding has not fully understood windows forms databindings
Юрген Штайнблок

4
@CraigBrett Рассматривайте BindingSourceкак мост между вашим источником данных и вашим графическим интерфейсом. Он решает многие проблемы, связанные с привязкой данных. Вы хотите перезагрузить данные? Просто установите bindingSource.DataSourceсвою новую коллекцию вместо того, чтобы повторно связывать каждый элемент управления. Ваш DataSource может быть нулевым? Установить bindingSource.DataSource = typeof(YourClass)Вы хотите иметь редактируемую сетку, но в вашем источнике данных нет конструктора без параметров? Просто реализуйте bindingSource.AddingNewсобытие и создайте объект самостоятельно. У меня никогда не было недостатков при использовании, BindingSourceно было много преимуществ.
Юрген Штайнблок

4

Каждый раз, когда вы добавляете новый элемент в список, вам необходимо повторно привязать свою сетку. Что-то типа:

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;

Я не вижу свойство dataSource в datagrid. Вы можете сказать мне, как мне его использовать?
RSB

2

Да, можно обойтись без повторной привязки, реализовав интерфейс INotifyPropertyChanged.

Довольно простой пример доступен здесь,

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


1
Этого недостаточно, если вы реализуете INotifyPropertyChangedDataGridView, он будет отображать все изменения свойств, которые происходят в фоновом режиме, но он не будет знать, добавляете ли вы / удаляете строку из своего источника. Для этого есть IBindingListинтерфейс и, для вашего удобства, BindingList<T>имплементация, которая уже реализует его, но не поддерживает сортировку / фильтрацию.
Юрген Штайнблок

1
Да, согласен с тобой. поэтому я думаю, что для этого можно использовать ObservableCollection <T>. Что вы думаете?
Dev

0

После добавления нового элемента personsдобавить:

myGrid.DataSource = null;
myGrid.DataSource = persons;

Я не вижу свойство dataSource в datagrid. Вы можете сказать мне, как мне его использовать?
RSB

1
Это предложение может вызвать проблемы. Например, вы можете обнаружить, что щелчок по элементу в сетке может вызвать исключение IndexOutOfRangeException. поскольку в этот момент источник данных имеет значение NULL. Было бы разумнее сначала привязать к BindingList и реализовать INotifyPropertyChanged на своем объекте, как указывают другие ответы
Стив

Какой смысл его назначать, nullесли сразу personsна следующей строке назначать ?
Руфус Л.

0

Это не совсем та проблема, с которой я столкнулся, но если кто-то хочет преобразовать BindingList любого типа в список того же типа, то вот как это делается:

var list = bindingList.ToDynamicList();

Кроме того, если вы назначаете BindingLists динамических типов DataGridView.DataSource, убедитесь, что вы сначала объявили его как IBindingList, чтобы все вышеперечисленное работало.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.