У меня есть два класса: Employee
и EmployeeGridViewAdapter
. Employee
состоит из нескольких составных типов. EmployeeGridViewAdapter
переносит сингл Employee
и подвергает его участников как сглаженный набор системных типов, таким образом, DataGridView может обработать отображение, редактирование, и т.д.
Я использую встроенную поддержку VS превращения ПОСТЕПЕННО в источник данных, который я затем присоединяю к a BindingSource
объект. Когда я присоединяю DataGridView
к BindingSource
это создает ожидаемые столбцы, и во времени выполнения я могу выполнить ожидаемые операции CRUD. Все хорошо до сих пор.
Проблемой является набор адаптеров, и набор сотрудников не синхронизируются. Так все сотрудники я создаю время выполнения, никогда не сохраняются. Вот отрывок кода, который генерирует набор EmployeeGridViewAdapter
:
var employeeCollection = new List<EmployeeGridViewAdapter>();
foreach (var employee in this.employees)
{
employeeCollection.Add(new EmployeeGridViewAdapter(employee));
}
this.view.Employees = employeeCollection;
Довольно прямой, но я не могу выяснить, как синхронизироваться, возвращается к исходному набору. Я предполагаю, что редактирования уже обрабатываются, потому что оба набора ссылаются на те же объекты, но создания новых сотрудников и удаления сотрудников не происходит так, я не могу быть уверен.
Первая проблема, похоже, заключается в том, что вы создаете новый список и связываете с ним данные. Когда вы добавляете элементы, они будут добавлены в коллекцию, но исходный список сотрудников останется неизменным.
Чтобы избежать этого, вы должны либо предоставить собственный класс коллекции, который будет переносить изменения обратно в базовый список сотрудников, либо подключить соответствующие события (для выполнения миграции при вставке / удалении) перед привязкой данных к нему.
Чтобы избежать ряда других проблем с привязкой редактируемых коллекций к сеткам, вы должны реализовать интерфейсы привязки данных, как описано ниже. Наличие этих интерфейсов позволяет визуальным элементам управления уведомлять базовую коллекцию о таких действиях, как «вставка отменена» (когда пользователи прерывают ввод новой записи), и аналогичным образом позволяет информации течь в противоположном направлении (обновлять пользовательский интерфейс, когда коллекция или отдельные записи меняются).
Во-первых, вы захотите реализовать как минимум IEditableObject, INotifyPropertyChanged и IDataErrorInfo для отдельных элементов в коллекции с привязкой к данным, которой в вашем случае будет класс EmployeeGridViewAdaper.
Кроме того, вы хотите, чтобы ваша коллекция реализовывала ITypedList и INotifyCollectionChanged. BCL содержит реализацию BindingList, которая является хорошей отправной точкой для этого. Рекомендуем использовать это вместо простого списка.
Я могу порекомендовать Связывание данных с Windows Forms 2.0 для исчерпывающего освещения этой темы.
Вы также можете рассмотреть возможность использования System.Collections.ObjectModel.ObservableCollection и подключения его события CollectionChanged . Это могло выглядеть примерно так.
ObservableCollection<EmployeeAdapter> observableEmployees =
new ObservableCollection<EmployeeAdapter>();
foreach (Employee emp in employees)
{
observableEmployees.Add(new EmployeeAdapter(emp));
}
observableEmployees.CollectionChanged +=
(object sender, NotifyCollectionChangedEventArgs e) =>
{
ObservableCollection<EmployeeAdapter> views =
sender as ObservableCollection<EmployeeAdapter>;
if (views == null)
return;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (EmployeeAdapter view in e.NewItems)
{
if (!employees.Contains(view.Employee))
employees.Add(view.Employee);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (EmployeeAdapter view in e.OldItems)
{
if (employees.Contains(view.Employee))
employees.Remove(view.Employee);
}
break;
default:
break;
}
};
Код предполагает следующие операторы using.
using System.Collections.ObjectModel;
using System.Collections.Specialized;
Если вам нужен интерфейс IList , вы также можете использовать System.ComponentModel.BindingList и подключить его к событию ListChanged . Это могло выглядеть так.
BindingList<EmployeeAdapter> empViews = new BindingList<EmployeeAdapter>();
foreach (Employee emp in employees)
{
empViews.Add(new EmployeeAdapter(emp));
}
empViews.ListChanged +=
(object sender, ListChangedEventArgs e) =>
{
BindingList<EmployeeAdapter> employeeAdapters =
sender as BindingList<EmployeeAdapter>;
if (employeeAdapters == null)
return;
switch (e.ListChangedType)
{
case ListChangedType.ItemAdded:
EmployeeAdapter added = employeeAdapters[e.NewIndex];
if (!employees.Contains(added.Employee))
employees.Add(added.Employee);
break;
case ListChangedType.ItemDeleted:
EmployeeAdapter deleted = employeeAdapters[e.OldIndex];
if (employees.Contains(deleted.Employee))
employees.Remove(deleted.Employee);
break;
default:
break;
}
};
Код предполагает следующий оператор using.
using System.ComponentModel;