Title: Why does the BindingSource.ListChanged event fire when moving through the items in the underlying list?
Tags: c#;winforms;data-binding
Question: I am trying to create a "Modified" or "Dirty" flag for the current record if one of the fields changes. I want to use the ListChanged event of the binding source to set the dirty flag. This works if I change the contents of the text box or select a different object in the combobox.
However, I noticed that the dirty flag is set (because the ListChanged event is fired) each time I navigate to a new record. I get that the content of the controls is changing when you move to a new item, but I thought the ListChanged event only fired with the actual properties of the list change, or an item is added or removed.
It is also interesting that the ListChanged event is fired even though my classes do not implement INotifyPropertyChange.
Here is my setup.
public partial class Form1 : Form
BindingList<ClassA&gt; records;
BindingSource bs;
public Form1()
InitializeComponent();
records = new BindingList<ClassA&gt;();
records.Add(new ClassA(1, new ClassB(1, "Label1")));
records.Add(new ClassA(2, new ClassB(2, "Label2")));
bs = new BindingSource() { DataSource = records };
bs.ListChanged += Bs_ListChanged;
bs.PositionChanged += Bs_PositionChanged;
List<ClassB&gt; labels = new List<ClassB&gt;();
labels.Add(new ClassB(1, "Label1"));
labels.Add(new ClassB(2, "Label2"));
labels.Add(new ClassB(3, "Label3"));
bindingNavigator1.BindingSource = bs;
comboBox1.DataSource = labels;
comboBox1.ValueMember = "ID";
comboBox1.DisplayMember = "Label";
textBox1.DataBindings.Add("Text", bs, "ID");
comboBox1.DataBindings.Add("SelectedItem", bs, "Nested");
private void Bs_ListChanged(object sender, ListChangedEventArgs e)
label1.Text = "Changed"; // visual representation of the dirty flag
And here are the 2 classes.
class ClassA
public int ID { get; set; }
public ClassB Nested { get; set; }
public ClassA (int id, ClassB b)
ID = id;
Nested = b;
class ClassB
public int ID { get; set; }
public string Label { get; set; }
public ClassB (int id, string label)
ID = id;
Label = label;
Comment: The `ComboBox.DataBinding` causes the selected value to set as the current `records` item value. So the underlying List changes. -- The ListChanged event is reaised by the BindingSource, not the BindingList.

Comment: `CurrentChanged` and `CurrentItemChanged` are event raised by the CurrencyManager, which is also used to hooks items changed events. You could avoid to use the BindingNavigator (which makes a mess behind the scene, raising Layout events all the time), create your own UI and use the BindingSource MoveNext, MovePrevious etc. methods. In this case, you can set `[BindingSource].RaiseListChangedEvents = false` before moving the Current item. BTW, if you use a BindingSource, a BindingList is ~useless, since the BindingSource creates a BindingList anyway when you set its DataSource.

Comment: If your classes need to implement `INotifyPropertyChanged`, you'd have to implement it anyway, BindingList or not BindingList.

Comment: BTW2, always set the `DisplayMember` (and `ValueMember`, since you're there) before you set the `DataSource`.

Comment: OK. I've decided not to use the ListChanged event in that way. I guess I'm wondering what the point of it is. It looks to me like CurrentChanged, CurrentItemChanged and ListChanged are all very similar and occur almost in the same circumstances.

Comment: Thanks Jimi for your insights. I decided to use a flag "moved" that is set to true whenever I move records. The ListChanged event then checks that flag and if it is false (a change occurred not resulting from moving) then the Dirty flag is set to true.



{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 0, 'CommentCount': 6, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2020:00:02/20/20', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<c#><winforms><data-binding>', 'Title': 'Why does the BindingSource.ListChanged event fire when moving through the items in the underlying list?', 'ViewCount': 315, 'id': 60326797, 'user_AboutMe': '<p>10 years Access VBA developer</p>\n\n<p>3 years T-SQL experience</p>\n\n<p>1 year C# experience (learning)</p>\n', 'user_AccountId': 15201037.0, 'user_DisplayName': 'Eedz', 'user_Reputation': 116.0, 'user_Views': 11.0, 'user_id': 10969038.0}}