I'm trying to bind a datagrid in WPF to my ViewModel so that it will update any cell changes to the database as well as allow the user to delete rows and add new rows. I've got part of it working but can't find a ELEGANT solution for the ADD and modify. here is the xaml
<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>
then in my view model method
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;
}
}
Deleting a row or modifying a row on the datagrid does not flow onto the database.
a) what other binding do i need to create in the xaml code that will detect these events
b) How do i detect a removed record or modified item in the view model so that I can update the datacontext if it won't automatically.
You could create a new ViewModel CLass:ItemGridVM to represent each row object ie ItemGridVM exposes the Item class properties you are binding in your datagrid. eg:
Now in yourMainViewModel you can create an Observable COllection of ItemGridVM as:
Now in case of any action on any row the command binds to ItemGridVM.So u get the row details as exposed properties. I resolved the same issue using this.(Pure MVVM)
Your data context doesn't exist at the time you would be making udpates. You are using a 'using' statement which destroys the context. The only reason you are seeing data is that you have forced a query to run against your DB (via the .ToList() statement). To answer your questions:
a) nothing more is needed specifically for binding b) Calling SaveChanges() on your InspectorGeneralEntities() context will update any changes in your db.
Just subscribe to the CollectionChanged event of your ObservableCollection. The event handler receives an instance of the NotifyCollectionChangedEventArgs class which contains a property 'Action' describing if rows have been added or removed. It also contains lists of the rows that have been added ('NewItems') or removed ('OldItems'). That should give you enough information to update your database.
You could implement INotifyPropertyChanged in your row ViewModel (class
ItemsList
I guess) and then subscribe to it, to find out if a row is dirty and needs to be updated in the database. The interface consists of a single eventPropertyChanged
that is to be raised in the property setters of your ViewModel whenever a value changes.You're right the NotifyCollectionChanged event comes too early for an immediate insert to the database. But you can flag the row as 'inserted' in the event handler and insert it as soon as the last property changed event (see above) required to complete the row occurs.
I see a couple of problems with the code in your question. But the reason why deleting a row is not reflected in the database is the .ToList() -- essentially you're creating a new list which is a copy of query and the grid is removing elements from that copy.
You should use a ListCollectionView and use a Filter instead of a linq statement.
Here's a sample showing how to do it:
1) Create a new WPF project called ListCollectionViewTest
2) In the MainWindow.xaml.cs cut&paste the following (should be in ViewModel but I'm too lazy)
3) In MainWindow.xaml cut&paste this: