I have a DataGrid simplified looking like this:
<DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding Parts}"
SelectedItem="{Binding SelectedPart}" >
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name, Mode=TwoWay}" />
<DataGridTemplateColumn Header="PartType" >
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.PartTypes}"
SelectedItem="{Binding PartType, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding PartType}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
My ViewModel looks something like this:
public class PartListViewModel
{
private ObservableCollection<Part> _parts;
public ObservableCollection<Part> Parts
{
get { return _parts; }
set
{
_parts = value;
OnPropertyChanged("Parts");
}
}
private Part _selectedPart;
public Part SelectedPart
{
get { return _selectedPart; }
set
{
_selectedPart = value;
OnPropertyChanged("SelectedPart");
}
}
}
Now I want changes to datagrid cells being stored immediately to the database. How to do that in MVVM?
Currently I listen to the OnCellEditEnding
event of the DataGrid and save the record in the code-behind. But that is pretty ugly:
private void DataGrid_OnCellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
var viewModel = (PartListViewModel) DataContext;
viewModel.SavePart((Part) e.Row.Item);
}
You can do something like this.
(you need to add reference to System.Windows.Interactivity
, you can download the assemblies from here)
Then add reference to the namespace in the XAML.
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<i:Interaction.Triggers>
<i:EventTrigger EventName="CellEditEnding">
<i:InvokeCommandAction Command="{Binding SomeCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
One way to do this is with an event broker like the EventAggregator that comes with the Prism libs.
When you add each Part entity ("model") into the Parts collection you can wrap it with its own viewmodel (PartViewModel), this can then listen for property updates in its constituent Part and then publish an update message through the event broker. You can then have a service that listens for (subscribes to) that message and saves the published payload (the payload can be the Part that was modified).
You could handle the PropertyChanged
event for all Part
objects in the view model:
public class PartListViewModel
{
private ObservableCollection<Part> _parts;
public ObservableCollection<Part> Parts
{
get { return _parts; }
set
{
if(_parts != null) _parts.CollectionChanged -= OnCollectionChanged;
_parts = value;
if (_parts != null) _parts.CollectionChanged += OnCollectionChanged;
//OnPropertyChanged("Parts");
}
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (object part in e.NewItems)
{
(part as INotifyPropertyChanged).PropertyChanged
+= new PropertyChangedEventHandler(PartPropertyChanged);
}
}
if (e.OldItems != null)
{
foreach (object part in e.OldItems)
{
(part as INotifyPropertyChanged).PropertyChanged
-= new PropertyChangedEventHandler(PartPropertyChanged);
}
}
}
private void PartPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "PartType")
{
//save to database...
}
}
}
This does the Part
class to implement INotifyPropertyChanged
of course.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With