2010-09-06 42 views
11

Estoy buscando un código/artículo de ejemplo que demuestre WPF DataGrid en acción con el patrón MVVM para agregar, actualizar y eliminar registros de la base de datos.Agregar, actualizar y eliminar WPF DataGrid usando MVVM

Tengo un requisito específico para permitir que el usuario inserte un nuevo registro utilizando DataGrid, no un nuevo formulario secundario.

Si alguien puede recomendar buenos recursos o proporcionar una muestra para esa tarea en particular, sería de gran ayuda para mí.

Respuesta

1

No conozco ningún buen artículo sobre el tema, pero no veo el problema; siempre que se vincule a un ObservableCollection o ListCollectionView que contenga objetos cuya clase tenga un constructor predeterminado (no creo que haya otras restricciones), DataGrid manejará las cosas bastante bien. La colección a la que se une debe tener alguna forma de agregar elementos nuevos, por lo que debe vincularse a ICollection o IEditableCollectionView; este último es el preferido, ya que tiene opciones específicas para controlar la creación de elementos; consulte AddNew, CanAddNew, etc. con el cual DataGrid funciona bien

+0

en mi caso el problema es determinar qué fila se cambia/borró – Musaab

+0

No estoy seguro de que te sigo. La forma en que los nuevos elementos trabajan con DataGrid es que hay un NewItemPlaceholder (que tiene la misma estructura que cualquier otra fila de cuadrícula de datos), que cuando se enfoca crea un nuevo elemento de datos temporales, y cuando se compromete (perdiendo el foco, ingresa la clave, etc.) se inserta ese artículo en la colección. IIRC todo está codificado mucho, así que tal vez no puedas cambiar todo lo que quieras, pero deberías intentarlo, siempre fue suficiente para mí. –

+0

Olvidémonos de los elementos nuevos, hablemos de los elementos existentes, cómo puedo eliminar una fila, eliminar significa eliminarla de la cuadrícula y de la base de datos también, aquí está mi problema – Musaab

2

Aquí en CodeProject es un artículo sobre el patrón de cuadrícula de datos WPF MVVM +:

http://www.codeproject.com/KB/WPF/MVVM_DataGrid.aspx

+1

El proyecto al que vinculó no agrega ni actualiza, y solo lo elimina utilizando un botón Eliminar, no con la fila de eliminación de DataGrid. ¡También me resulta extremadamente frustrante intentar encontrar ejemplos del mundo real sobre cómo usar MVVM para operaciones CRUD usando un DataGrid! Estoy empezando a pensar que MVVM es un mito. – SurfingSanta

1

Editar: Pegado la parte, que se adapte a su pregunta. Artículo completo: http://www.codeproject.com/Articles/30905/WPF-DataGrid-Practical-Examples

Este ejemplo demuestra cómo usar un DataGrid para realizar operaciones CRUD a través del enlace donde la integración de la base de datos está desacoplada mediante una capa de acceso a datos (DAL).

La Arquitectura

Este ejemplo es una aplicación CRUD simple que permite al usuario editar los elementos de la tabla Clientes de la base de datos Neptuno. El ejemplo tiene una capa de acceso a datos, que expone métodos de búsqueda/eliminación/actualización que operan en objetos de datos simples, y una capa de presentación que adapta estos objetos de manera que el marco WPF pueda vincularlos eficazmente. Debido a que solo realizamos funciones CRUD, no he agregado una Capa lógica de negocios (BLL); si eres un purista, podrías agregar un BLL de paso; sin embargo, creo que agregaría poco a este ejemplo.

Las clases clave dentro de esta arquitectura se muestran a continuación:

La capa de acceso de datos expone una interfaz para la gestión del ciclo de vida de los objetos de datos de los clientes. La clase que implementa esta interfaz usa un DataSet tipado como una capa de integración de base de datos; sin embargo, esto está oculto para los clientes de DAL. La presencia de esta capa significa que no se acoplan directamente con el esquema de base de datos o el esquema de base de datos generada, es decir, podemos cambiar nuestro esquema, aún así proporcionar la interfaz dada a continuación a nuestros clientes:

public interface ICustomerDataAccessLayer 
{ 
    /// Return all the persistent customers 
    List<CustomerDataObject> GetCustomers(); 

    /// Updates or adds the given customer 
    void UpdateCustomer(CustomerDataObject customer); 

    /// Delete the given customer 
    void DeleteCustomer(CustomerDataObject customer); 
} 
public class CustomerDataObject 
{ 
    public string ID { get; set; } 

    public string CompanyName { get; set; } 

    public string ContactName { get; set; } 
} 

Como puede ver, no hay interfaces o clases específicas de infraestructura de interfaz de usuario (como ObservableCollection) expuestas por el DAL. El problema aquí es cómo vincular a los clientes devueltos por ICustomerDataAccess.GetCustomers a nuestro DataGrid y garantizar que los cambios se sincronicen con la base de datos.

Podría enlazar el DataGrid directamente a nuestra colección de clientes, Lista; sin embargo, debemos asegurarnos de que los métodos UpdateCustomer y DeleteCustomer en nuestra interfaz DAL se invoquen en los momentos apropiados.Un enfoque que podríamos tomar es manejar los eventos/comandos expuestos por DataGrid para determinar qué acción acaba de realizar o tiene la intención de realizar en la colección de clientes enlazados. Sin embargo, al hacerlo, estaríamos escribiendo código de integración que es específico de DataGrid. ¿Qué pasaría si quisiéramos cambiar la interfaz de usuario para presentar un ListView y varios TextBoxes (vista de detalles)? Tendríamos que volver a escribir esta lógica. Además, ninguno de los eventos de DataGrid encaja con lo que queremos. Hay eventos de "finalización", pero no eventos "finalizados"; por lo tanto, los datos visibles para los manejadores de eventos no se encuentran en su estado comprometido. Un mejor enfoque sería si pudiéramos adaptar nuestra colección de objetos del Cliente de tal manera que pudieran vincularse a cualquier control de interfaz de usuario de WPF adecuado, con operaciones de agregar/editar/eliminar sincronizadas con la base de datos a través de nuestro DAL. Manejo de operaciones de eliminación

La clase ObservableCollection es un buen candidato para nuestras necesidades de enlace de datos. Expone un evento CollectionChanged que se activa cada vez que se agregan o eliminan elementos de la colección. Si copiamos los datos de nuestros clientes en un ObservableCollection y lo vinculamos al DataGrid, podemos manejar el evento CollectionChanged y realizar la operación requerida en el DAL. El siguiente fragmento de código muestra cómo CustomerObjectDataProvider (que se define como ObjectDataProvider en XAML) construye una ObservableCollection de CustomerUIObjects. Estos objetos de interfaz de usuario simplemente envuelven sus contrapartes de objeto de datos para exponer las mismas propiedades.

public CustomerObjectDataProvider() 
{ 
    dataAccessLayer = new CustomerDataAccessLayer(); 
} 

public CustomerUIObjects GetCustomers() 
{ 
    // populate our list of customers from the data access layer 
    CustomerUIObjects customers = new CustomerUIObjects(); 

    List<CustomerDataObject> customerDataObjects = dataAccessLayer.GetCustomers(); 
    foreach (CustomerDataObject customerDataObject in customerDataObjects) 
    { 
     // create a business object from each data object 
     customers.Add(new CustomerUIObject(customerDataObject)); 
    } 

    customers.CollectionChanged += new 
     NotifyCollectionChangedEventHandler(CustomersCollectionChanged); 

    return customers; 
} 

void CustomersCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
{ 
    if (e.Action == NotifyCollectionChangedAction.Remove) 
    { 
     foreach (object item in e.OldItems) 
     { 
      CustomerUIObject customerObject = item as CustomerUIObject; 

      // use the data access layer to delete the wrapped data object 
      dataAccessLayer.DeleteCustomer(customerObject.GetDataObject()); 
     } 
    } 
} 

Cuando un usuario elimina una fila con el control DataGrid, se desencadena el evento CollectionChanged en la colección enlazada. En el controlador de eventos, invocamos el método DAL DeleteCustomer con el objeto de datos envuelto pasado como el parámetro.

Manejar las operaciones de eliminación es relativamente sencillo, pero ¿qué hay de las actualizaciones o inserciones? Puede pensar que se puede usar el mismo enfoque, la propiedad NotifyCollectionChangedEventArgs.Action incluye Agregar operaciones; sin embargo, este evento no se activa cuando los elementos de la colección se actualizan. Además, cuando un usuario agrega un nuevo elemento a DataGrid, el objeto se agrega inicialmente a la colección enlazada en un estado no inicializado, por lo que solo veríamos el objeto con sus valores de propiedad predeterminados. Lo que realmente necesitamos hacer es determinar cuándo el usuario termina de editar un elemento en la grilla. Manejo de actualizaciones/inserciones

Para determinar cuándo un usuario termina de editar un elemento encuadernado, tenemos que ahondar un poco más en el mecanismo de encuadernación. El DataGrid puede realizar una confirmación atómica de la fila que se está editando actualmente; Esto es posible si los elementos enlazados implementan la interfaz IEditableObject que expone los métodos BeginEdit, EndEdit y CancelEdit. Normalmente, un objeto que implementa esta interfaz volverá a su estado en el momento en que se invocó el método BeginEdit como respuesta al método CancelEdit invocado. Sin embargo, en este caso, no estamos realmente interesados ​​en poder cancelar las modificaciones; todo lo que realmente necesitamos saber es cuándo el usuario ha terminado de editar una fila. Esto se procesa cuando DataGrid invoca EndEdit en nuestro elemento vinculado.

Con el fin de notificar a la CustomerDataObjectProvider que EndEdit ha sido invocada en uno de los objetos de la colección encuadernada, la CustomerUIObject implementa IEditableObject de la siguiente manera:

public delegate void ItemEndEditEventHandler(IEditableObject sender); 

public event ItemEndEditEventHandler ItemEndEdit; 

#region IEditableObject Members 

public void BeginEdit() {} 

public void CancelEdit() {} 

public void EndEdit() 
{ 
    if (ItemEndEdit != null) 
    { 
     ItemEndEdit(this); 
    } 
} 

#endregion 

Cuando los elementos se añaden a la colección CustomerUIObjects, este evento se maneja para todos los elementos de la colección, con el manejador de simplemente enviar el evento:

public class CustomerUIObjects : ObservableCollection<CustomerDataObject> 
{ 
    protected override void InsertItem(int index, CustomerUIObject item) 
    { 
     base.InsertItem(index, item); 

     // handle any EndEdit events relating to this item 
     item.ItemEndEdit += new ItemEndEditEventHandler(ItemEndEditHandler); 
    } 

    void ItemEndEditHandler(IEditableObject sender) 
    { 
     // simply forward any EndEdit events 
     if (ItemEndEdit != null) 
     { 
      ItemEndEdit(sender); 
     } 
    } 

    public event ItemEndEditEventHandler ItemEndEdit; 
} 

el CustomerObjectDataProvider puede ahora manejar este evento para recibir la notificación de CommitEdit se invoca en cualquiera de los elementos enlazados.A continuación, puede invocar los métodos DAL para sincronizar el estado de base de datos:

public CustomerUIObjects GetCustomers() 
{ 
    // populate our list of customers from the data access layer 
    CustomerUIObjects customers = new CustomerUIObjects(); 

    List<CustomerDataObject> customerDataObjects = dataAccessLayer.GetCustomers(); 
    foreach (CustomerDataObject customerDataObject in customerDataObjects) 
    { 
     // create a business object from each data object 
     customers.Add(new CustomerUIObject(customerDataObject)); 
    } 

    customers.ItemEndEdit += new ItemEndEditEventHandler(CustomersItemEndEdit); 
    customers.CollectionChanged += new 
     NotifyCollectionChangedEventHandler(CustomersCollectionChanged); 

    return customers; 
} 

void CustomersItemEndEdit(IEditableObject sender) 
{ 
    CustomerUIObject customerObject = sender as CustomerUIObject; 

    // use the data access layer to update the wrapped data object 
    dataAccessLayer.UpdateCustomer(customerObject.GetDataObject()); 
} 

El código anterior manejar tanto las operaciones de inserción y actualización.

En conclusión, este método adapta los elementos de datos y la recopilación proporcionados por el DAL en elementos de UI y colecciones que son más apropiados para el enlace de datos dentro del Marco de WPF. Toda la lógica de sincronización de la base de datos se realiza mediante el manejo de eventos de esta colección enlazada; por lo tanto, no hay un código específico de WPF DataGrid.

+1

Si bien este enlace puede responder la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace de referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia. – IngoAlbers

Cuestiones relacionadas