Как правильно прибиндить коллекцию к DataGridView?

Я точно знаю, как это делается в WPF+MVVM через реализацию INotifyPropertyChanged. Но вот с WinForms я застрял и потерпел поражение.

Задача состоит в том, чтобы не трогать DataSource у таблицы в процессе выполнения кода, а максимум на этапе инициализации. Но у меня не получилось реализовать это через dataGridView1.DataBindings.Add("DataSource", ItemsList, nameof(ItemsList)), ловлю исключение, говорящее о том, что так нельзя.

System.ArgumentException: 'Cannot bind to the property or column ItemsList on the DataSource.
Parameter name: dataMember'

Гуглил, читал англоязычные доки, но меня это не спасло.

В результате я сдался, и сделал вот так.

private BindingList<MyClass> _itemsList;

public BindingList<MyClass> ItemsList
{
    get => _itemsList;
    set
    {
        _itemsList = value; 
        dataGridView1.DataSource = ItemsList;
    }
}

А как это делают опытные WinForms разработчики? В смысле не бизнес-логику, а техническую реализацию, чтобы можно было писать в свойство, а табличка перезагружала бы данные из источника сама? Вдруг я что-то упустил.

Сразу оговорюсь, в шаблоне MVP у меня опыта ноль, и сейчас приложение напоминает классическую мешанину из обработчиков событий в классах типа Form. Но есть план сделать по-взрослому, вот и ищу потенциальные методики взаимодействия с интерфейсом, чтобы, как говорят грамотные люди: "отделить логику от представления".

Мигрировать проект на WPF буду, но не сейчас, а скорее после стабильного релиза .NET 5. А сейчас просто хочется причесать древний код, повыкидывать костыли, чтобы миграция потом не превратилась в написание проекта с нуля.


Ответы (1 шт):

Автор решения: Alexander Petrov

Третьим параметром привязки идёт имя свойства источника данных, а не имя самого источника.

В каком классе расположено свойство ItemsList? Судя по тому, что идёт прямое обращение к датагриду, оно расположено в классе формы.

Тогда привязку следует делать так:

dataGridView1.DataBindings.Add("DataSource", this, nameof(ItemsList));

Где this - указатель на форму (или, в общем случае, на экземпляр класса, содержащего свойство ItemsList).

В сеттере, естественно, при этом не должно быть dataGridView1.DataSource = ItemsList;


Несколько смущает, что ItemsList является публичным свойством. Значит, в любой момент может быть присвоен новый BindingList<MyClass> откуда-то извне. При этом нужно сделать повторную привязку. А перед этим удалить предыдущую. И за всем этим должен следить тот, кто извне задаёт это свойство...


С учётом всего этого, вариант сеттера с заданием привязки является гораздо более простым и правильным.


Мне не нравятся названия наподобие ItemsList, UserCollection и т. п. Ведь это венгерская нотация в худшем её проявлении. Только вместо префикса - суффикс типа. Я бы писал просто Items, Users и т. п.

→ Ссылка