You need to have your data carrier class implement INotifyPropertyChanged or
provide a <property>Changed event for each of the properties exposed.
Failure to do this will have the data update in one binding scenarion but
changes won't be seen if the object is bound to two objects such as ina
master-detail view.
Well, you can do without INotifyPropertyChanged in many cases, but anything other than simply DataBinding cases you will have to notify the controls of a change in the underlying source (or vice versa if you want to get notified of all changes or just validated changes).
A modified version of the previous code sample has a new Button (button2) and a TextBox (textBox1) added. Clicking button2 will change the second MyObject's Text property in code.
Instead of binding the grid directly to the object list, dataGridView1 is now bound to a BindingSource containing the list. The BindingSource can then keep track of the selected row in the grid and use this information to display details in other controls. Not to mention how easy it isto add new items in the grid by setting BindingSource.AllowNew (note, this requires a dynamic list as well as a default constructor in the object) The sample uses a single property "Text" displayed in the grid and the TextBox, but the TextBox could just as well be bound to properties not displayed in the grid.
Notice the commented line in the setter in the Text property. This calls NotifyPropertyChanged which is a method firing the PropertyChanged event telling all the controls bound to this property to update the view. To see the effect, select the second row in the grid and click button2 with and without the line commented out. If the control isn't notified, the data is still changed, but it won't be displayed until the data is normally read (like selecting the row again). You may also notice that if the row isn't selected, the grid isn't updated either, even if it is notified. I don't remember exactly why, but the BindingSource doesn't appear to keep track of nonselected members.
public partial class Form1 : Form
{
private List<MyClass> strings = new List<MyClass>();
public Form1()
{
InitializeComponent();
strings.Add(new MyClass("Hello"));
strings.Add(new MyClass("World"));
BindingSource s = new BindingSource(strings, "");
s.AllowNew = true; // Lets us add new items in the grid
dataGridView1.DataSource = s;
textBox1.DataBindings.Add("Text", s, "Text");
}
private class MyClass : INotifyPropertyChanged
{
string s;
public string Text
{
get { return s; }
set
{
s = value;
// Uncomment the line below
//NotifyPropertyChanged("Text");
}
}
// Default constructor needed to add new items in the grid
public MyClass() { }
public MyClass(string s)
{
Text = s;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string property)
{
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
private void button1_Click(object sender, EventArgs e)
{
string s = "";
foreach (MyClass c in strings)
s += c.Text + Environment.NewLine;
MessageBox.Show(s);
}
private void button2_Click(object sender, EventArgs e)
{
strings[1].Text = "Night";
}
}