Синхронизация коллекции обернутых объектов с коллекцией развернутых объектов - PullRequest
9 голосов
/ 11 марта 2010

У меня есть два класса: Employee и EmployeeGridViewAdapter. Employee состоит из нескольких сложных типов. EmployeeGridViewAdapter оборачивает один Employee и выставляет его элементы в виде плоского набора типов систем, чтобы DataGridView мог обрабатывать отображение, редактирование и т. Д.

Я использую встроенную поддержку VS для превращения POCO в источник данных, который затем присоединяю к объекту 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;

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

Ответы [ 2 ]

3 голосов
/ 25 марта 2010

Вы также можете рассмотреть возможность использования 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 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 System.ComponentModel;
1 голос
/ 24 марта 2010

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

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

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

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

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

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

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