question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Bind Model to Winforms DataGridView, can not get old value when property changed

See original GitHub issue

.NET version

.Net 8.0 Preview 4

Did it work in .NET Framework?

No

Did it work in any of the earlier releases of .NET Core or .NET 5+?

No response

Issue description

I have a Model (INotifyPropertyChanged) and bound to a DataGridView by BindingList, Once I edited a property of model instance, DataGridView’s cell value updated before PropertyChanged raied. I have no idea why.

I am going to listen to BindingList’s ListChanged (ItemChanged) event and get new value and old value of updating property, but DataGridView’s cell value updated before raising this event, so that I can not get old value from DatGridView’s cell.

Does anyone has some others solution to get both of new and old values when model’s property changed? Great thanks!

Steps to reproduce

Here is my code:

public partial class Form1 : Form
{
    public abstract class BindableBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;

        protected bool SetProperty<TValue>(ref TValue field, TValue newValue, [CallerMemberName] string propertyName = "")
        {
            if (EqualityComparer<TValue>.Default.Equals(field, newValue))
            {
                return false;
            }

            var dataGridView = Application.OpenForms.OfType<Form1>().First().dataGridView1;
            if (dataGridView.RowCount > 0)
                Debug.Print($"Before set value to field: {dataGridView.Rows[0].Cells[0].Value}");
            field = newValue;
            if (dataGridView.RowCount > 0)
                Debug.Print($"After set value to field But before raise PropertyChanged event: {dataGridView.Rows[0].Cells[0].Value}");
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            if (dataGridView.RowCount > 0)
                Debug.Print($"After raise PropertyChanged event: {dataGridView.Rows[0].Cells[0].Value}");
            return true;
        }
    }

    public class Model : BindableBase
    {
        private int age;

        public int Age { get => age; set => this.SetProperty(ref this.age, value); }
    }

    BindingList<Model> Models = new();

    public Form1()
    {
        this.InitializeComponent();
        this.dataGridView1.AutoGenerateColumns = true;
        this.dataGridView1.DataSource = this.Models;
        this.dataGridView1.Click += this.DataGridView1_Click;
    }

    private void DataGridView1_Click(object? sender, EventArgs e)
    {
        switch (this.dataGridView1.RowCount)
        {
            case 0:
                this.Models.Add(new Model() { Age = 10 });
                break;
            default:
                this.Models[0].Age = DateTime.Now.Microsecond;
                break;
        }
    }

Here is some logs, you can see that Cell value was updated when set value to field and before raising PropertyChanged event;

Before set value to field: 10
After set value to field But before raise PropertyChanged event: 478
After raise PropertyChanged event: 478

Before set value to field: 478
After set value to field But before raise PropertyChanged event: 744
After raise PropertyChanged event: 744

Issue Analytics

  • State:closed
  • Created 3 months ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
tboloncommented, Jun 7, 2023

I don’t think there is anything wrong in this behavior: the DataGridView does not store a copy of your value, he just use the model’s value when asked, so when you call dataGridView.Rows[0].Cells[0].Value, the datagridview calls Model.Age on your model, which returns the new value since you just updated the field.

The only goal of this event is to indicate the control that the value has been updated “recently”, and that the control should reread the value and update its display accordingly (for example). There is no concept of previous/new value.

INotifyPropertyChanging was added for this exact case: if you need to get the previous and the new value, then you have should implement and subscribe to this event.

In my opinion, storing a value before/after change should be handled by your model directly (like storing the previous value in a different field, exposed as a “PreviousAge” property for example), and not depending on the datagridview, the UI, or the databinding engine itself.

1reaction
Olina-Zhangcommented, Jun 7, 2023

@Olina-Zhang can one of your team please look into this?

We got the same result as the code provided in this issue. But needs our engineering team to look into it about codes.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why listbox and datagridview does not update
Hi, I am relatively new to C# and am learning WindowsFormApp at the moment. My questions are related to listbox and datagridview please....
Read more >
Data Binding in Windows Forms DataGrid (SfDataGrid)
WinForms DataGrid control is designed to display the bounded data in a tabular format. ... event is raised when the DataModel property value...
Read more >
A Detailed Data Binding Tutorial
Demonstrates a variety of Windows Forms data binding features through several simple examples.
Read more >
Wpf datagrid cell events. It also occurs when the user ...
Now you know which item the user has selected (clicked on). Make that property = PropertyChanged and use the setter for the updated...
Read more >
Professional C# 4.0 and .NET 4 - Page 1128 - Google Books Result
If the values in the list are wide, you can change the width of the drop-down ... however, the DisplayMember and ValueMember properties...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found