简体   繁体   中英

What is the best way to know if the user has changed data in the DataGrid?

I would like to know every time a user modifies data in WPF DataGrid.

Is there a single event that I can use to do that? Or what is the minimal set of events that I can use to cover full set of data changes (Add row, delete row, modify row etc)?

I know that this is probably more than you are asking for, but once you do it, it's hard to go back. Whatever you are binding to ... some List, have that item implement IEditableObject. that way you won't have to ever worry about whatever control/view implementation, events ets. When the item is changed, the datagrid as well as plethora of .NET controls will set the IsDirty object to true.

These are not super great links but they will get you started thinking about maintaining isDirty flag.

https://msdn.microsoft.com/en-us/library/system.componentmodel.ieditableobject(v=vs.110).aspx

object editing and isDirty() flag

http://bltoolkit.net/doc/EditableObjects/EditableObject.htm

this is more what I am used to:

https://stackoverflow.com/a/805695/452941

Usually, when you are using MVVM, you bind the master list to an ObservableCollection and then the selected item to a specific instance. Inside your setters, you can raise events. This would be the most logical (read: the most common method I've seen) to capture updates / adds / deletes to a list of data.

MainWindow.xaml

<Window x:Class="WpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication"
        Title="MainWindow" Height="350" Width="525">
    <DataGrid x:Name="dataGrid" AutoGeneratingColumn="OnAutoGeneratingColumn">
        <DataGrid.Resources>
            <Style TargetType="DataGridCell">
                <EventSetter Event="Binding.SourceUpdated" Handler="OnDataGridCellSourceUpdated"/>
                <EventSetter Event="Binding.TargetUpdated" Handler="OnDataGridCellTargetUpdated"/>
            </Style>
        </DataGrid.Resources>
    </DataGrid>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        this.dataGrid.ItemsSource = new ObservableCollection<Person>()
        {
            new Person() { Name = "John", Surname = "Doe" },
            new Person() { Name = "Jane", Surname = "Doe" }
        };
    }

    private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        var dataGridBoundColumn = e.Column as DataGridBoundColumn;
        if (dataGridBoundColumn != null)
        {
            var binding = dataGridBoundColumn.Binding as Binding;
            if (binding != null)
            {
                binding.NotifyOnSourceUpdated = true;
                binding.NotifyOnTargetUpdated = true;
            }
        }
    }

    private void OnDataGridCellSourceUpdated(object sender, DataTransferEventArgs e)
    {
        this.OnDataGridCellChanged((DataGridCell)sender);
    }

    private void OnDataGridCellTargetUpdated(object sender, DataTransferEventArgs e)
    {
        this.OnDataGridCellChanged((DataGridCell)sender);
    }

    private void OnDataGridCellChanged(DataGridCell dataGridCell)
    {
        // DataContext is MS.Internal.NamedObject for NewItemPlaceholder row.
        var person = dataGridCell.DataContext as Person;
        if (person != null)
        {
            var propertyName = ((Binding)((DataGridBoundColumn)dataGridCell.Column).Binding).Path.Path;
            var propertyValue = TypeDescriptor.GetProperties(person)[propertyName].GetValue(person);
            // TODO: do some logic here.
        }
    }
}

This is what I used for some complex DataGridCell formatting based on a Person (just some POCO) instance, property name and property value.

But if you want to be able to know when to save the data and you use MVVM, then the best way to do this would be to have original value and current value for every editable property in your view model / model. When data is loaded, original and current value would be equal, and if property is changed through DataGrid or any other way, only current value is updated. When data needs to be saved, just check if any item has any property that has different original and current value. If the answer is yes, then data should be saved, because it has been changed since last load / save, otherwise data is same as when loaded, so no new saving is required. Also, when saving, current values must be copied to original values, because data is again equal to the saved data, like when it was last loaded.

if you use mvvm you do not need to know when the "user modify data in the data grid" you have to know when the underlying collection change .

so if you use datatable(HasChanges/RejectChanges...) you have that all built in. if you use poco collections then your items at least have to implement INotifyPropertyChanged - if its raised the user modify data. Maybe IEditable is a good one too for reject changes and so on.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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