marsh-wiggle
marsh-wiggle

Reputation: 2813

DataGrid - Event which fires after CellEditEnding()

I have a DataGrid associated with a List <> of objects (ItemsSource). In the CellEditEnding () event, I change the data of the linked object list. To refresh the DataGrid, it must be refreshed:

this.DataGridFieldProperties.Items.Refresh();

Invoking the update from code within the CellEditEnding() event throws an InvalidOperationException.

Question:
Is there an event triggered after CellEditEnding()?

What I have tried so far
Multiple events, such as GotFocus, ColumnDisplayIndexChanged(), etc., and two-way bindings. But none of them works reliably and refreshing the DataGrid in an asynchronous thread (async event with Task.Run())

Example

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Button Name="Btn_FillGrid" Click="Btn_FillGrid_Click"/>
    <DataGrid Name="DataGrid_SOExample" Grid.Row="1" AutoGenerateColumns="False" CanUserAddRows="False" IsReadOnly="False" CellEditEnding="DataGrid_SOExample_CellEditEnding">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Generic1"/>
            <DataGridTextColumn Header="Generic2"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>



public partial class Win_SOExample : Window
{
    public Win_SOExample()
    {
        InitializeComponent();
    }

    private void Btn_FillGrid_Click(object sender, RoutedEventArgs e)
    {
        List<SoExample> soExampList = new List<SoExample>();
        soExampList.Add(new SoExample() { Field1 = "Row0 Field1", Field2 = "Row0 Field2" });
        soExampList.Add(new SoExample() { Field1 = "Row1 Field1", Field2 = "Row1 Field2" });
        soExampList.Add(new SoExample() { Field1 = "Row2 Field1", Field2 = "Row2 Field2" });

        (this.DataGrid_SOExample.Columns[0] as DataGridTextColumn).Binding = new Binding("Field1") { Mode = BindingMode.TwoWay };
        (this.DataGrid_SOExample.Columns[1] as DataGridTextColumn).Binding = new Binding("Field2") { Mode = BindingMode.TwoWay };
        this.DataGrid_SOExample.ItemsSource = soExampList;
    }

    private async void DataGrid_SOExample_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
    {
        if(e.EditAction == DataGridEditAction.Commit)
        {
            // after the user finished the edit, data in other rows needs to get updatet

            // simple example
            List<SoExample> soExampList = (this.DataGrid_SOExample.ItemsSource as List<SoExample>);
            soExampList[1].Field1 = DateTime.Now.ToLongDateString();

            await Task.Yield();
            this.DataGrid_SOExample.Items.Refresh();
        }
    }

    private class SoExample
    {
        public string Field1 { get; set; } = "";
        public string Field2 { get; set; } = "";
    }
}

Upvotes: 2

Views: 485

Answers (1)

mm8
mm8

Reputation: 169400

You should implement INotifyPropertyChanged in your SoExample class:

private class SoExample : INotifyPropertyChanged
{
    private string _field1;
    public string Field1
    {
        get { return _field1; }
        set { _field1 = value; NotifyPropertyChanged(); }
    }

    private string _field2;
    public string Field2
    {
        get { return _field2; }
        set { _field2 = value; NotifyPropertyChanged(); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Then you can set the property to a new value without refreshing:

private async void DataGrid_SOExample_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
    if (e.EditAction == DataGridEditAction.Commit)
    {
        List<SoExample> soExampList = (this.DataGrid_SOExample.ItemsSource as List<SoExample>);
        soExampList[1].Field1 = DateTime.Now.ToLongDateString();
    }
}

Upvotes: 2

Related Questions