0

I've got a test WPF application using Caliburn.Micro. I'm trying to build with a DataGrid that can be edited. The data will update the database when a cell/row gets updated.

The issue I'm running into though is that when my RowEditEnding event gets triggered. It passes the information in the row before the row was edited. I'm wondering how I can get the updated information passed to the function.

Any help would be appreciated. Relevant code below:

View:

<DataGrid x:Name="People"
          AutoGenerateColumns="False"
          CanUserReorderColumns="True"
          CanUserAddRows="True"
          AlternatingRowBackground="#dfdfdf"
          cal:Message.Attach="[Event RowEditEnding] = [Action SavePeopleEdit($this)]">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding FirstName}">
            <DataGridTextColumn.Header>
                <TextBlock Text="First"
                           ToolTip="This Persons First Name" />
            </DataGridTextColumn.Header>
        </DataGridTextColumn>
        <DataGridTextColumn Binding="{Binding LastName}">
            <DataGridTextColumn.Header>
                <TextBlock Text="Last"
                           ToolTip="This Persons Last Name" />
            </DataGridTextColumn.Header>
        </DataGridTextColumn>
        <DataGridTextColumn Binding="{Binding pNumber}">
            <DataGridTextColumn.Header>
                <TextBlock Text="Person Number"
                           ToolTip="This Persons pNumber" />
            </DataGridTextColumn.Header>
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid> 

ViewModel:

using Caliburn.Micro;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;

namespace SqliteEncryptionTest.ViewModels
{

public class ShellViewModel : Screen
{
    public IObservableCollection<PersonModel> _people;
    public IObservableCollection<PersonModel> People {
        get { return _people; }
        set {
            _people = value;
            NotifyOfPropertyChange(() => People);
            } 
        }

        public void SavePeopleEdit(object sender)
        {
            if (People != null)
            {
            MessageBox.Show(People[3].LastName.ToString());
            }
        }

        public ShellViewModel()
        {
            LoadPeopleList();
        }

        private void LoadPeopleList()
        {
            People = new BindableCollection<PersonModel>(SqliteDataAccess.LoadPeople());
        }

    }
} 

enter image description here I changed LastName to "Four", but it still shows the value to be "4".

Corey
  • 835
  • 1
  • 9
  • 32
  • Does this answer your question? [WPF Datagrid Row Editing "ENDED" event](https://stackoverflow.com/questions/3938040/wpf-datagrid-row-editing-ended-event) – Pavel Anikhouski Jan 10 '20 at 20:53
  • @PavelAnikhouski I'm trying to keep away from using code in the code-behind of the `.xaml` `View`. Using `cal:Message.Attach="[Event RowEditEnding] = [Action SavePeopleEdit($this)]"` is essentially the same thing. Which works fine, it's just running before the edit really seems to take place. I need the data after the edit so that I can update the database. – Corey Jan 10 '20 at 21:02
  • 2
    Does the settings `UpdateSourceTrigger=PropertyChanged` in Binding will help? – Pavel Anikhouski Jan 10 '20 at 21:16
  • @PavelAnikhouski Using Caliburn.Micro I believe already does that when you attach a property like `x:Name="People"`. Which has the `NotifyOfPropertyChange()` in the full property. – Corey Jan 10 '20 at 21:41
  • 1
    there is nothing related to caliburn.micro or INPC in my comment above, [`UpdateSourceTrigger`](https://learn.microsoft.com/en-us/dotnet/api/system.windows.data.updatesourcetrigger?view=netframework-4.8) describes when binding source will be updated – Pavel Anikhouski Jan 11 '20 at 14:55
  • 1
    And this is already answered in this [thread](https://stackoverflow.com/questions/10388466/wpf-datagrid-celleditended-event/27239243) – Pavel Anikhouski Jan 11 '20 at 16:27
  • @PavelAnikhouski Thanks, that makes sense. I'll try that out when I'm in front of my code again Monday. – Corey Jan 12 '20 at 16:14

1 Answers1

1

It seems this was hinted at by Pavel Anikhouski in a comment on the original post, but I'll clarify this as an answer.

This is because RowEditEnding (and CellEditEnding) is executed just before the edit is committed (see this doc post) so you can stop or edit change if you wish, you could grab the data that has been changed as shown in this SO answer

The best option however is to add UpdateSourceTrigger=PropertyChanged to the binding of each of the DataGrid columns you would like to have update as they are edited, this will update the model as each change is made, before RowEditEnding is executed.

<DataGrid x:Name="People"
          AutoGenerateColumns="False"
          cal:Message.Attach="[Event CellEditEnding] = [Action SavePeopleEdit($sender, $eventArgs)]">
<DataGrid.Columns>
    <!-- Will update while changed -->
    <DataGridTextColumn Header="First" Binding="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}"/> 

    <!-- Will not update until after the change is committed -->
    <DataGridTextColumn Header="Last" Binding="{Binding LastName}"/> 
</DataGrid.Columns>

Zach R
  • 181
  • 3
  • 15