WPF DataGrid: немедленное сохранение изменений ячеек с помощью MVVM

У меня упрощенный 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);
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
0
443
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете сделать что-то вроде этого. (нужно добавить ссылку на 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, конечно.

Другие вопросы по теме