Как правильно прибиндить коллекцию к 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 шт):
Третьим параметром привязки идёт имя свойства источника данных, а не имя самого источника.
В каком классе расположено свойство ItemsList? Судя по тому, что идёт прямое обращение к датагриду, оно расположено в классе формы.
Тогда привязку следует делать так:
dataGridView1.DataBindings.Add("DataSource", this, nameof(ItemsList));
Где this - указатель на форму (или, в общем случае, на экземпляр класса, содержащего свойство ItemsList).
В сеттере, естественно, при этом не должно быть dataGridView1.DataSource = ItemsList;
Несколько смущает, что ItemsList является публичным свойством. Значит, в любой момент может быть присвоен новый BindingList<MyClass> откуда-то извне. При этом нужно сделать повторную привязку. А перед этим удалить предыдущую. И за всем этим должен следить тот, кто извне задаёт это свойство...
С учётом всего этого, вариант сеттера с заданием привязки является гораздо более простым и правильным.
Мне не нравятся названия наподобие ItemsList, UserCollection и т. п. Ведь это венгерская нотация в худшем её проявлении. Только вместо префикса - суффикс типа. Я бы писал просто Items, Users и т. п.