У меня упрощенный DataGrid выглядит так:
<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>
Моя ViewModel выглядит примерно так:
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");
}
}
}
Теперь я хочу, чтобы изменения в ячейках сетки данных немедленно сохранялись в базе данных. Как это сделать в MVVM?
В настоящее время я слушаю событие OnCellEditEnding DataGrid и сохраняю запись в коде программной части. Но это очень некрасиво:
private void DataGrid_OnCellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
var viewModel = (PartListViewModel) DataContext;
viewModel.SavePart((Part) e.Row.Item);
}





Вы можете сделать что-то вроде этого.
(нужно добавить ссылку на System.Windows.Interactivity, скачать сборки можно отсюда)
Затем добавьте ссылку на пространство имен в 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>
Один из способов сделать это — использовать брокер событий, такой как Агрегатор событий, который поставляется с библиотеками Prism.
Когда вы добавляете каждую сущность Part («модель») в коллекцию Parts, вы можете обернуть ее собственной моделью представления (PartViewModel), которая затем может прослушивать обновления свойств в составной части, а затем публиковать сообщение об обновлении через брокера событий. Затем у вас может быть служба, которая прослушивает (подписывается) на это сообщение и сохраняет опубликованную полезную нагрузку (полезной нагрузкой может быть часть, которая была изменена).
Вы можете обработать событие PropertyChanged для всех Part объектов в модели представления:
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...
}
}
}
Это делает класс Part для реализации INotifyPropertyChanged, конечно.