2010-03-11 21 views
9

Tengo dos clases: Employee y EmployeeGridViewAdapter. Employee se compone de varios tipos complejos. EmployeeGridViewAdapter envuelve un solo Employee y expone sus miembros como un conjunto aplanado de tipos de sistemas por lo que un DataGridView puede manejar visualización, edición, etc.Sincronización de una colección de objetos envueltos con una colección de objetos sin envolver

estoy usando soporte nativo de VS para convertir a poco en una fuente de datos, que luego adjuntar a un objeto BindingSource. Cuando adjunto el DataGridView al BindingSource crea las columnas esperadas y en el tiempo de ejecución puedo realizar las operaciones esperadas de CRUD. Todo está bien hasta ahora.

El problema es la recopilación de adaptadores y la recopilación de empleados no se está sincronizando. Entonces todos los empleados que creo un tiempo de ejecución nunca se mantienen. He aquí un fragmento del código que genera el cobro de EmployeeGridViewAdapter 's:

 var employeeCollection = new List<EmployeeGridViewAdapter>(); 
     foreach (var employee in this.employees) 
     { 
      employeeCollection.Add(new EmployeeGridViewAdapter(employee)); 
     } 
     this.view.Employees = employeeCollection; 

bastante sencillo, pero no puedo encontrar la manera de sincronizar los cambios de nuevo a la colección original. Me imagino que las ediciones ya se están manejando porque ambas colecciones hacen referencia a los mismos objetos, pero la creación de nuevos empleados y la eliminación de empleados no están sucediendo, así que no puedo estar seguro.

+0

@Kenneth: ¿Qué hiciste para resolver tu problema? – VoidDweller

+0

¿Qué le parece aplicar la solución ObservableViewModelCollection a http://stackoverflow.com/questions/1256793/mvvm-sync-collections. –

Respuesta

1

El primer problema parece ser que está creando una nueva lista y un enlace de datos a eso. Cuando agregue elementos, estos se agregarán a la colección, pero su lista de empleados original no se modificará.

Para evitar esto, debe proporcionar una clase de recopilación personalizada que migrará los cambios a la lista de empleados subyacente o conectar los eventos apropiados (para realizar la migración al insertar/eliminar) antes de vincularlos.

Para evitar una serie de otros problemas al enlazar colecciones editables a grillas, debe implementar las interfaces de enlace de datos, como se describe a continuación. La presencia de estas interfaces permite a los controles visuales notificar a la colección subyacente sobre acciones como "inserción cancelada" (cuando los usuarios cancelan la entrada de un nuevo registro) y permite que la información fluya en la dirección opuesta (actualizar la IU cuando se recolecta o las entradas cambian).

Primero, querrá implementar al menos IEditableObject, INotifyPropertyChanged e IDataErrorInfo en los elementos individuales de una colección enlazada a datos, que en su caso sería la clase EmployeeGridViewAdaper.

Además, querría que su colección implementara ITypedList e INotifyCollectionChanged. El BCL contiene una implementación de BindingList que proporciona un buen punto de partida para esto. Recomiende usar esto en lugar de la lista simple.

Puedo recomendar Data Binding with Windows Forms 2.0 para una cobertura exhaustiva de este tema.

3

También podría considerar usar System.Collections.ObjectModel.ObservableCollection y cablear su evento CollectionChanged. Podría verse algo como esto.

 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; 
       } 
      }; 

El código asume las siguientes instrucciones de uso.

using System.Collections.ObjectModel; 
using System.Collections.Specialized; 

Si necesita la interfaz IList también se podría utilizar System.ComponentModel.BindingList y el alambre hasta que es ListChanged evento. Podría verse así.

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; 
       } 
      }; 

El código asume la siguiente instrucción de uso.

using System.ComponentModel; 
Cuestiones relacionadas