2011-08-10 46 views
8

Estoy intentando vincular una cuadrícula de datos en WPF a mi ViewModel para que actualice los cambios de celda en la base de datos y permita al usuario eliminar filas y agregar nuevas filas. Tengo una parte de ella funcionando pero no puedo encontrar una solución ELEGANTE para ADD y modificar. aquí es el xamlWPF datagrid con MVVM

<DataGrid AutoGenerateColumns="false" HorizontalAlignment="Left" Margin="26,41,0,0" Name="dataGrid1" 
       ItemsSource="{Binding Path=GetAllItems}" Height="200" VerticalAlignment="Top" Width="266" > 
     <DataGrid.Columns> 
      <DataGridTextColumn Binding="{Binding Path=ItemListID}" Header="ID" Visibility="Hidden"/> 
      <DataGridTextColumn Binding="{Binding Path=ItemName}" Header="Name" Width="4*" /> 
      <DataGridCheckBoxColumn Binding="{Binding Path=IsActive}" Header="Active" Width="*" /> 
     </DataGrid.Columns> 

continuación, en mi opinión, el método modelo

private ObservableCollection< ItemsList> getAllItems() 
{ 
    using (var context = new InspectorGeneralEntities()) 
    { 
     var query = from I in context.ItemsLists 
        select I; 

     var item = new ObservableCollection<ItemsList>(query.ToList()); 
     return item; 
    } 
} 

Supresión de una fila o modificar una fila en la cuadrícula de datos no fluye en la base de datos.

a) ¿qué otra unión ¿Es necesario crear en el código XAML que detectará estos eventos

b) ¿Cómo puedo detectar un registro eliminado o elemento modificado en el modelo de vista para que pueda actualizar el DataContext si no lo hará automáticamente

Respuesta

1

Simplemente suscríbase al evento CollectionChanged de su ObservableCollection. El controlador de eventos recibe una instancia de la clase NotifyCollectionChangedEventArgs que contiene una propiedad 'Acción' que describe si las filas se han agregado o eliminado. También contiene listas de las filas que se han agregado ('NewItems') o eliminado ('OldItems'). Eso debería darle suficiente información para actualizar su base de datos.

Puede implementar INotifyPropertyChanged en su fila ViewModel (clase ItemsList, supongo) y suscribirse, para averiguar si una fila está sucia y necesita actualizarse en la base de datos. La interfaz consiste en un solo evento PropertyChanged que se debe generar en los conjuntos de propiedades de su ViewModel siempre que cambie un valor.

Tiene razón, el evento NotifyCollectionChanged llega demasiado pronto para una inserción inmediata en la base de datos. Pero puede marcar la fila como 'insertada' en el controlador de eventos e insertarla tan pronto como ocurra el último evento de propiedad cambiada (ver arriba) requerido para completar la fila.

+1

dos cuestiones.; 1) NotifyCollectionChangedAction sólo se disparará si se agrega una nueva fila o Eliminar fila existente y NO si modifica una celda en una fila existente. es decir, no hay forma de saber si la fila está sucia. 2) Al empezar a escribir la nueva fila de la NotifyCollectionChangedAction.Add se disparó antes de haber tenido la oportunidad de rellenar todas las células. No puede agregar una fila vacía a la base de datos especialmente si todavía hay campos nulos en este punto. Así que de nuevo debes usar la Actualización ... que de nuevo no puedo entender cómo capturar. – Josef

1

Veo un par de problemas con el código en su pregunta. Pero la razón por la cual eliminar una fila no se refleja en la base de datos es .ToList() - esencialmente está creando una nueva lista que es una copia de la consulta y la cuadrícula está eliminando elementos de esa copia.

Debe utilizar un ListCollectionView y utilizar un filtroen lugar de una declaración de LINQ.

Aquí hay un ejemplo que muestra cómo hacerlo:

1) Crear un nuevo proyecto llamado WPF ListCollectionViewTest

2) En los MainWindow.xaml.cs cortar & pegue el siguiente (debe estar en ViewModel pero yo soy demasiado perezoso)

using System.Collections.Generic; 
    using System.Linq; 
    using System.Windows; 
    using System.Windows.Data; 

    namespace ListCollectionViewTest 
    { 
     /// <summary> 
     /// Interaction logic for MainWindow.xaml 
     /// </summary> 
     public partial class MainWindow : Window 
     { 
      private List<Employee> equivalentOfDatabase = new List<Employee>() 
         { 
          new Employee() { FirstName = "John", LastName = "Doe", IsWorthyOfAttention = true }, 
          new Employee() { FirstName = "Jane", LastName = "Doe", IsWorthyOfAttention = true }, 
          new Employee() { FirstName = "Mr.", LastName = "Unsignificant", IsWorthyOfAttention = false }, 
         }; 

      public ListCollectionView TestList { get; set; } 
      public MainWindow() 
      { 
       DataContext = this; 

       // This is all the magic you need ------- 
       TestList = new ListCollectionView(equivalentOfDatabase); 
       TestList.Filter = x => (x as Employee).IsWorthyOfAttention; 

       InitializeComponent(); 
      } 

      private void Button_Click(object sender, RoutedEventArgs e) 
      { 
       MessageBox.Show(equivalentOfDatabase.Aggregate("Employees are: \n\r", (acc, emp) => acc + string.Format(" - {0} {1}\n\r", emp.FirstName, emp.LastName), x => x)); 
      } 
     } 

     public class Employee 
     { 
      public string FirstName { get; set; } 
      public string LastName { get; set; } 
      public bool IsWorthyOfAttention { get; set; } 
     } 
    } 

3) En MainWindow.xaml cortar & pega este:

<Window x:Class="ListCollectionViewTest.MainWindow" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      Title="MainWindow" Height="350" Width="525"> 

     <StackPanel> 
      <DataGrid ItemsSource="{Binding TestList}" 
         RowHeight="22" 
         AutoGenerateColumns="True"> 
      </DataGrid> 
      <Button Content="Show All Employees in DB" Click="Button_Click" /> 
     </StackPanel>   
    </Window> 
0

Su contexto de datos no existe en el momento en que estaría haciendo udpates.Está utilizando una declaración 'using' que destruye el contexto. La única razón por la que está viendo datos es porque ha forzado una consulta para que se ejecute en su base de datos (a través de la declaración .ToList()). Para responder a sus preguntas:

a) no se necesita nada más específicamente para el enlace b) Llamar a SaveChanges() en su contexto InspectorGeneralEntities() actualizará cualquier cambio en su base de datos.

0

Se puede crear un nuevo modelo de vista Clase: ItemGridVM para representar cada objeto de fila es decir ItemGridVM expone las propiedades de la clase de artículos que son vinculantes en su cuadrícula de datos. por ejemplo:

public class ItemGridVM : BaseViewModel 
    { 
    private Item _item;//an instance of Item class 
     public int ItemId 
       { 
        get 
        { 
         return _item.ItemId; 
        } 
        set 
        { 
         _item.ItemId = value; 
         //if you want UI changes : raise PropertyChanged Notification and binding in UI should be Update SourceTrigger:PropertyChanged 
        } 
     } 
    //Contains Commands :UpdateItem,EditItem,DeleteItem 
} 

Ahora en yourMainViewModel puede crear una colección observable de ItemGridVM como:

private ObservableCollection<ItemGridVM> _getAllItems; 

public ObservableCollection<ItemGridVM> GetAllItems 
{ 
get 
      { 
       return _getAllItems; 
      } 
      set 
      { 
       _getAllItems = value; 
       //if u want Observable Collection to get updated on edit either 
       RaisePropertyChanged("GetAllItems"); 

      } 
} 

Ahora bien, en caso de cualquier acción en cualquier fila de la orden se une a ItemGridVM.So u obtener la fila detalles como propiedades expuestas. que resuelven el mismo problema usando este (MVVM puro)