Search code examples
c#wpfeventsdatagridcaliburn.micro

WPF Caliburn.Micro DataGrid Cell not updating before Event


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".


Solution

  • 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>