Синхронизация набора перенесенных объектов с набором развернутых объектов

У меня есть два класса: 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;

Довольно прямой, но я не могу выяснить, как синхронизироваться, возвращается к исходному набору. Я предполагаю, что редактирования уже обрабатываются, потому что оба набора ссылаются на те же объекты, но создания новых сотрудников и удаления сотрудников не происходит так, я не могу быть уверен.

9
задан Kenneth Cochran 11 March 2010 в 05:35
поделиться

2 ответа

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

Чтобы избежать этого, вы должны либо предоставить собственный класс коллекции, который будет переносить изменения обратно в базовый список сотрудников, либо подключить соответствующие события (для выполнения миграции при вставке / удалении) перед привязкой данных к нему.

Чтобы избежать ряда других проблем с привязкой редактируемых коллекций к сеткам, вы должны реализовать интерфейсы привязки данных, как описано ниже. Наличие этих интерфейсов позволяет визуальным элементам управления уведомлять базовую коллекцию о таких действиях, как «вставка отменена» (когда пользователи прерывают ввод новой записи), и аналогичным образом позволяет информации течь в противоположном направлении (обновлять пользовательский интерфейс, когда коллекция или отдельные записи меняются).

Во-первых, вы захотите реализовать как минимум IEditableObject, INotifyPropertyChanged и IDataErrorInfo для отдельных элементов в коллекции с привязкой к данным, которой в вашем случае будет класс EmployeeGridViewAdaper.

Кроме того, вы хотите, чтобы ваша коллекция реализовывала ITypedList и INotifyCollectionChanged. BCL содержит реализацию BindingList, которая является хорошей отправной точкой для этого. Рекомендуем использовать это вместо простого списка.

Я могу порекомендовать Связывание данных с Windows Forms 2.0 для исчерпывающего освещения этой темы.

1
ответ дан 3 November 2019 в 07:47
поделиться

Вы также можете рассмотреть возможность использования 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;
3
ответ дан 3 November 2019 в 07:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: