简体   繁体   English

WPF DataGrid:使用MVVM立即保存单元格更改

[英]WPF DataGrid: Save cell changes immediately with MVVM

I have a DataGrid simplified looking like this: 我有一个简化的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>

My ViewModel looks something like this: 我的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");
        }
    }
}

Now I want changes to datagrid cells being stored immediately to the database. 现在我希望将datagrid单元格的更改立即存储到数据库中。 How to do that in MVVM? 如何在MVVM中做到这一点?

Currently I listen to the OnCellEditEnding event of the DataGrid and save the record in the code-behind. 目前我收听DataGrid的OnCellEditEnding事件并将记录保存在代码隐藏中。 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 ) (你需要添加对System.Windows.Interactivity引用, 你可以从这里下载程序集

Then add reference to the namespace in the XAML. 然后在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. 一种方法是使用事件代理,例如Prism库附带的EventAggregator

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. 将每个Part实体(“model”)添加到Parts集合中时,您可以使用自己的viewmodel(PartViewModel)将其包装,然后可以在其组成部分中侦听属性更新,然后通过事件代理发布更新消息。 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: 您可以处理视图模型中所有Part对象的PropertyChanged事件:

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. 这当然是Part类实现INotifyPropertyChanged

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM