Reputation: 14507
I know I should be able to solve this myself, but I've been banging my head on the desk for hours.
I have a list of items in a DGV, and want the DGV to update when the properties change (one property in this case). Below is a complete sample that reproduces the problem. The output of the program is:
Marking item 'One' as Missing
Status changing
Status changed has a listener
Marking item 'Two' as Missing
Status changing
Marking item 'Three' as Missing
Status changing
Marking item 'Four' as Missing
Status changing
You see the change occur on the DGV only for the first item. As you can see from that output, the BindingSource is listening for property changes on the first item in the list and passing notice to the DGV, but not for any of the others.
What am I missing here?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Forms;
class Form1 : Form
{
private enum ModuleStatus
{
Ok,
Missing,
}
private sealed class ModuleInfo : INotifyPropertyChanged
{
public string Label { get; set; }
private ModuleStatus _status;
public ModuleStatus Status
{
get { return _status; }
set
{
if (_status != value)
{
Trace.WriteLine(String.Format("Status changing"));
_status = value;
OnPropertyChanged("Status");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
Trace.WriteLine(String.Format("Status changed has a listener"));
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
private List<ModuleInfo> moduleList = new List<ModuleInfo>();
private BindingSource moduleBinding;
private Timer timer = new Timer { Enabled = true, Interval = 1000 };
public Form1()
{
moduleBinding = new BindingSource(moduleList, null);
Controls.Add(new DataGridView
{
Dock = DockStyle.Fill, AutoGenerateColumns = false, AllowUserToAddRows = false, RowHeadersVisible = false,
Columns =
{
new DataGridViewTextBoxColumn { HeaderText = "Label", DataPropertyName = "Label", AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill, ReadOnly = true },
new DataGridViewTextBoxColumn { HeaderText = "Status", DataPropertyName = "Status", ReadOnly = true },
},
DataSource = moduleBinding,
});
foreach (string label in new string[] { "One", "Two", "Three", "Four" })
moduleBinding.Add(new ModuleInfo { Label = label, Status = ModuleStatus.Ok });
timer.Tick += new EventHandler(timer_Tick);
}
int modifyIndex = 0;
void timer_Tick(object sender, EventArgs e)
{
if (modifyIndex < moduleList.Count)
{
Trace.WriteLine(String.Format("Marking item '{0}' as Missing", moduleList[modifyIndex].Label));
moduleList[modifyIndex].Status = ModuleStatus.Missing;
modifyIndex++;
}
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
Upvotes: 1
Views: 1386
Reputation: 4999
change your moduleList to this:
private BindingList<ModuleInfo> moduleList = new BindingList<ModuleInfo>();
you may or may not find this post helpful: BindingList vs List
Upvotes: 2