prosh0t
asked on
simple data binding not working - ArrayList of Customer objects to textbox's
Hello,
I have an arrayList of 'clsCustomer' objects. Each 'clsCustomer' object has the properties: strFirst, strLast, and strAddress. I have a form with 3 text box's : txtFirst, txtLast, and txtAddress. I bound the arraylist to the textbox's with this code:
txtFirst.DataBindings.Add( "Text", arrCustomer, "strFirst");
txtLast.DataBindings.Add(" Text", arrCustomer, "strLast");
txtAddress.DataBindings.Ad d("Text", arrCustomer, "strAddress");
I can increment the BindingContext (see btnInc_Click below) and all of the text box's will change correctly. However, if code is executed to modify the customer object currently displayed, the GUI text fields are not updated.
When the following code is executed in 'btnChange_Click' I expect txtAddress to show the changed value on the GUI but it does not:
((clsCustomer)arrCustomer[ 0]).strAdd ress = "Changed address";
I already have implemented INotifyPropertyChanged in the clsCustomer class. Any ideas?
Thanks.
You can see the problem of my program by pasting the following code into a new VS 2005 C# project form, then starting it up and pressing the button 'Add Binding', and then pressing the button 'change address'. The 'change address' button appears to do nothing but you would expect it to change the data displayed in the txtAddress text box.
Here is all of the code for the simple form (along with the clsCustomer class):
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
using System.Data.OleDb;
using System.Text.RegularExpress ions;
namespace dnUtil
{
public class Form1 : System.Windows.Forms.Form
{
#region Windows Form Designer generated code
public System.Windows.Forms.Butto n btnInc;
public System.Windows.Forms.Butto n btnAdd;
private dnUtil.Controls.TextBoxDro ppable txtFirst;
private dnUtil.Controls.TextBoxDro ppable txtLast;
private dnUtil.Controls.TextBoxDro ppable txtAddress;
private Label txtStatus;
public Button btnChange;
public System.Windows.Forms.Butto n btnExit;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
}
base.Dispose( disposing );
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnInc = new System.Windows.Forms.Butto n();
this.btnAdd = new System.Windows.Forms.Butto n();
this.btnExit = new System.Windows.Forms.Butto n();
this.folderBrowserDialog1 = new System.Windows.Forms.Folde rBrowserDi alog();
this.openFileDialog1 = new System.Windows.Forms.OpenF ileDialog( );
this.txtStatus = new System.Windows.Forms.Label ();
this.btnChange = new System.Windows.Forms.Butto n();
this.txtAddress = new dnUtil.Controls.TextBoxDro ppable();
this.txtLast = new dnUtil.Controls.TextBoxDro ppable();
this.txtFirst = new dnUtil.Controls.TextBoxDro ppable();
this.SuspendLayout();
//
// btnInc
//
this.btnInc.BackColor = System.Drawing.SystemColor s.Control;
this.btnInc.Cursor = System.Windows.Forms.Curso rs.Default ;
this.btnInc.Font = new System.Drawing.Font("Arial ", 8F, System.Drawing.FontStyle.R egular, System.Drawing.GraphicsUni t.Point, ((byte)(0)));
this.btnInc.ForeColor = System.Drawing.SystemColor s.ControlT ext;
this.btnInc.Location = new System.Drawing.Point(266, 79);
this.btnInc.Name = "btnInc";
this.btnInc.RightToLeft = System.Windows.Forms.Right ToLeft.No;
this.btnInc.Size = new System.Drawing.Size(105, 24);
this.btnInc.TabIndex = 33;
this.btnInc.Text = "Increment Binding";
this.btnInc.UseVisualStyle BackColor = false;
this.btnInc.Click += new System.EventHandler(this.b tnInc_Clic k);
//
// btnAdd
//
this.btnAdd.BackColor = System.Drawing.SystemColor s.Control;
this.btnAdd.Cursor = System.Windows.Forms.Curso rs.Default ;
this.btnAdd.Font = new System.Drawing.Font("Arial ", 8F, System.Drawing.FontStyle.R egular, System.Drawing.GraphicsUni t.Point, ((byte)(0)));
this.btnAdd.ForeColor = System.Drawing.SystemColor s.ControlT ext;
this.btnAdd.Location = new System.Drawing.Point(266, 6);
this.btnAdd.Name = "btnAdd";
this.btnAdd.RightToLeft = System.Windows.Forms.Right ToLeft.No;
this.btnAdd.Size = new System.Drawing.Size(105, 24);
this.btnAdd.TabIndex = 32;
this.btnAdd.Text = "Add Binding";
this.btnAdd.UseVisualStyle BackColor = false;
this.btnAdd.Click += new System.EventHandler(this.b tnAdd_Clic k);
//
// btnExit
//
this.btnExit.BackColor = System.Drawing.SystemColor s.Control;
this.btnExit.Cursor = System.Windows.Forms.Curso rs.Default ;
this.btnExit.Font = new System.Drawing.Font("Arial ", 8F, System.Drawing.FontStyle.R egular, System.Drawing.GraphicsUni t.Point, ((byte)(0)));
this.btnExit.ForeColor = System.Drawing.SystemColor s.ControlT ext;
this.btnExit.Location = new System.Drawing.Point(298, 109);
this.btnExit.Name = "btnExit";
this.btnExit.RightToLeft = System.Windows.Forms.Right ToLeft.No;
this.btnExit.Size = new System.Drawing.Size(73, 24);
this.btnExit.TabIndex = 31;
this.btnExit.Text = "E&xit";
this.btnExit.UseVisualStyl eBackColor = false;
this.btnExit.Click += new System.EventHandler(this.b tnExit_Cli ck);
//
// txtStatus
//
this.txtStatus.AutoSize = true;
this.txtStatus.Location = new System.Drawing.Point(51, 177);
this.txtStatus.Name = "txtStatus";
this.txtStatus.Size = new System.Drawing.Size(0, 13);
this.txtStatus.TabIndex = 46;
//
// btnChange
//
this.btnChange.BackColor = System.Drawing.SystemColor s.Control;
this.btnChange.Cursor = System.Windows.Forms.Curso rs.Default ;
this.btnChange.Font = new System.Drawing.Font("Arial ", 8F, System.Drawing.FontStyle.R egular, System.Drawing.GraphicsUni t.Point, ((byte)(0)));
this.btnChange.ForeColor = System.Drawing.SystemColor s.ControlT ext;
this.btnChange.Location = new System.Drawing.Point(266, 36);
this.btnChange.Name = "btnChange";
this.btnChange.RightToLeft = System.Windows.Forms.Right ToLeft.No;
this.btnChange.Size = new System.Drawing.Size(105, 24);
this.btnChange.TabIndex = 47;
this.btnChange.Text = "Change Address";
this.btnChange.UseVisualSt yleBackCol or = false;
this.btnChange.Click += new System.EventHandler(this.b tnChange_C lick);
//
// txtAddress
//
this.txtAddress.AllowDrop = true;
this.txtAddress.Location = new System.Drawing.Point(7, 93);
this.txtAddress.Name = "txtAddress";
this.txtAddress.Size = new System.Drawing.Size(181, 20);
this.txtAddress.TabIndex = 45;
//
// txtLast
//
this.txtLast.AllowDrop = true;
this.txtLast.Location = new System.Drawing.Point(7, 67);
this.txtLast.Name = "txtLast";
this.txtLast.Size = new System.Drawing.Size(115, 20);
this.txtLast.TabIndex = 44;
//
// txtFirst
//
this.txtFirst.AllowDrop = true;
this.txtFirst.Location = new System.Drawing.Point(7, 41);
this.txtFirst.Name = "txtFirst";
this.txtFirst.Size = new System.Drawing.Size(115, 20);
this.txtFirst.TabIndex = 43;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(384, 141);
this.Controls.Add(this.btn Change);
this.Controls.Add(this.txt Status);
this.Controls.Add(this.txt Address);
this.Controls.Add(this.txt Last);
this.Controls.Add(this.txt First);
this.Controls.Add(this.btn Inc);
this.Controls.Add(this.btn Add);
this.Controls.Add(this.btn Exit);
this.Name = "Form1";
this.Text = "BindingTest (1.0.0)";
this.Load += new System.EventHandler(this.F orm1_Load) ;
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
ArrayList arrCustomer = new ArrayList();
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void Form1_Load(object sender, System.EventArgs e)
{
clsCustomer cCust = new clsCustomer();
cCust.strFirst = "cory";
cCust.strLast = "dosijy";
cCust.strAddress = "sacramento, ca";
arrCustomer.Add(cCust);
cCust = new clsCustomer();
cCust.strFirst = "bob";
cCust.strLast = "smith";
cCust.strAddress = "101 via vallejo ave";
arrCustomer.Add(cCust);
}
private void btnExit_Click(object sender, System.EventArgs e)
{
this.Close();
}
private void btnAdd_Click(object sender, EventArgs e)
{
txtFirst.DataBindings.Add( "Text", arrCustomer, "strFirst");
txtLast.DataBindings.Add(" Text", arrCustomer, "strLast");
txtAddress.DataBindings.Ad d("Text", arrCustomer, "strAddress");
}
private void btnInc_Click(object sender, EventArgs e)
{
if (this.BindingContext[arrCu stomer].Po sition > 0)
this.BindingContext[arrCus tomer].Pos ition = 0;
else
this.BindingContext[arrCus tomer].Pos ition++;
}
private void btnChange_Click(object sender, EventArgs e)
{
((clsCustomer)arrCustomer[ 0]).strAdd ress = "Changed address";
}
}
public class clsCustomer : INotifyPropertyChanged
{
private string _strFirst = "";
private string _strLast = "";
private string _strAddress = "";
public string strFirst
{
get
{
return _strFirst;
}
set
{
_strFirst = value;
PropertyChangedNotify("str First");
}
}
public string strLast
{
get
{
return _strLast;
}
set
{
_strLast = value;
PropertyChangedNotify("str Last");
}
}
public string strAddress
{
get
{
return _strAddress;
}
set
{
_strAddress = value;
PropertyChangedNotify("str Address");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandle r PropertyChanged;
private void PropertyChangedNotify(stri ng strProperty)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(s trProperty ));
}
}
#endregion
}
}
I have an arrayList of 'clsCustomer' objects. Each 'clsCustomer' object has the properties: strFirst, strLast, and strAddress. I have a form with 3 text box's : txtFirst, txtLast, and txtAddress. I bound the arraylist to the textbox's with this code:
txtFirst.DataBindings.Add(
txtLast.DataBindings.Add("
txtAddress.DataBindings.Ad
I can increment the BindingContext (see btnInc_Click below) and all of the text box's will change correctly. However, if code is executed to modify the customer object currently displayed, the GUI text fields are not updated.
When the following code is executed in 'btnChange_Click' I expect txtAddress to show the changed value on the GUI but it does not:
((clsCustomer)arrCustomer[
I already have implemented INotifyPropertyChanged in the clsCustomer class. Any ideas?
Thanks.
You can see the problem of my program by pasting the following code into a new VS 2005 C# project form, then starting it up and pressing the button 'Add Binding', and then pressing the button 'change address'. The 'change address' button appears to do nothing but you would expect it to change the data displayed in the txtAddress text box.
Here is all of the code for the simple form (along with the clsCustomer class):
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
using System.Data.OleDb;
using System.Text.RegularExpress
namespace dnUtil
{
public class Form1 : System.Windows.Forms.Form
{
#region Windows Form Designer generated code
public System.Windows.Forms.Butto
public System.Windows.Forms.Butto
private dnUtil.Controls.TextBoxDro
private dnUtil.Controls.TextBoxDro
private dnUtil.Controls.TextBoxDro
private Label txtStatus;
public Button btnChange;
public System.Windows.Forms.Butto
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
}
base.Dispose( disposing );
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnInc = new System.Windows.Forms.Butto
this.btnAdd = new System.Windows.Forms.Butto
this.btnExit = new System.Windows.Forms.Butto
this.folderBrowserDialog1 = new System.Windows.Forms.Folde
this.openFileDialog1 = new System.Windows.Forms.OpenF
this.txtStatus = new System.Windows.Forms.Label
this.btnChange = new System.Windows.Forms.Butto
this.txtAddress = new dnUtil.Controls.TextBoxDro
this.txtLast = new dnUtil.Controls.TextBoxDro
this.txtFirst = new dnUtil.Controls.TextBoxDro
this.SuspendLayout();
//
// btnInc
//
this.btnInc.BackColor = System.Drawing.SystemColor
this.btnInc.Cursor = System.Windows.Forms.Curso
this.btnInc.Font = new System.Drawing.Font("Arial
this.btnInc.ForeColor = System.Drawing.SystemColor
this.btnInc.Location = new System.Drawing.Point(266, 79);
this.btnInc.Name = "btnInc";
this.btnInc.RightToLeft = System.Windows.Forms.Right
this.btnInc.Size = new System.Drawing.Size(105, 24);
this.btnInc.TabIndex = 33;
this.btnInc.Text = "Increment Binding";
this.btnInc.UseVisualStyle
this.btnInc.Click += new System.EventHandler(this.b
//
// btnAdd
//
this.btnAdd.BackColor = System.Drawing.SystemColor
this.btnAdd.Cursor = System.Windows.Forms.Curso
this.btnAdd.Font = new System.Drawing.Font("Arial
this.btnAdd.ForeColor = System.Drawing.SystemColor
this.btnAdd.Location = new System.Drawing.Point(266, 6);
this.btnAdd.Name = "btnAdd";
this.btnAdd.RightToLeft = System.Windows.Forms.Right
this.btnAdd.Size = new System.Drawing.Size(105, 24);
this.btnAdd.TabIndex = 32;
this.btnAdd.Text = "Add Binding";
this.btnAdd.UseVisualStyle
this.btnAdd.Click += new System.EventHandler(this.b
//
// btnExit
//
this.btnExit.BackColor = System.Drawing.SystemColor
this.btnExit.Cursor = System.Windows.Forms.Curso
this.btnExit.Font = new System.Drawing.Font("Arial
this.btnExit.ForeColor = System.Drawing.SystemColor
this.btnExit.Location = new System.Drawing.Point(298, 109);
this.btnExit.Name = "btnExit";
this.btnExit.RightToLeft = System.Windows.Forms.Right
this.btnExit.Size = new System.Drawing.Size(73, 24);
this.btnExit.TabIndex = 31;
this.btnExit.Text = "E&xit";
this.btnExit.UseVisualStyl
this.btnExit.Click += new System.EventHandler(this.b
//
// txtStatus
//
this.txtStatus.AutoSize = true;
this.txtStatus.Location = new System.Drawing.Point(51, 177);
this.txtStatus.Name = "txtStatus";
this.txtStatus.Size = new System.Drawing.Size(0, 13);
this.txtStatus.TabIndex = 46;
//
// btnChange
//
this.btnChange.BackColor = System.Drawing.SystemColor
this.btnChange.Cursor = System.Windows.Forms.Curso
this.btnChange.Font = new System.Drawing.Font("Arial
this.btnChange.ForeColor = System.Drawing.SystemColor
this.btnChange.Location = new System.Drawing.Point(266, 36);
this.btnChange.Name = "btnChange";
this.btnChange.RightToLeft
this.btnChange.Size = new System.Drawing.Size(105, 24);
this.btnChange.TabIndex = 47;
this.btnChange.Text = "Change Address";
this.btnChange.UseVisualSt
this.btnChange.Click += new System.EventHandler(this.b
//
// txtAddress
//
this.txtAddress.AllowDrop = true;
this.txtAddress.Location = new System.Drawing.Point(7, 93);
this.txtAddress.Name = "txtAddress";
this.txtAddress.Size = new System.Drawing.Size(181, 20);
this.txtAddress.TabIndex = 45;
//
// txtLast
//
this.txtLast.AllowDrop = true;
this.txtLast.Location = new System.Drawing.Point(7, 67);
this.txtLast.Name = "txtLast";
this.txtLast.Size = new System.Drawing.Size(115, 20);
this.txtLast.TabIndex = 44;
//
// txtFirst
//
this.txtFirst.AllowDrop = true;
this.txtFirst.Location = new System.Drawing.Point(7, 41);
this.txtFirst.Name = "txtFirst";
this.txtFirst.Size = new System.Drawing.Size(115, 20);
this.txtFirst.TabIndex = 43;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(384, 141);
this.Controls.Add(this.btn
this.Controls.Add(this.txt
this.Controls.Add(this.txt
this.Controls.Add(this.txt
this.Controls.Add(this.txt
this.Controls.Add(this.btn
this.Controls.Add(this.btn
this.Controls.Add(this.btn
this.Name = "Form1";
this.Text = "BindingTest (1.0.0)";
this.Load += new System.EventHandler(this.F
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
ArrayList arrCustomer = new ArrayList();
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void Form1_Load(object sender, System.EventArgs e)
{
clsCustomer cCust = new clsCustomer();
cCust.strFirst = "cory";
cCust.strLast = "dosijy";
cCust.strAddress = "sacramento, ca";
arrCustomer.Add(cCust);
cCust = new clsCustomer();
cCust.strFirst = "bob";
cCust.strLast = "smith";
cCust.strAddress = "101 via vallejo ave";
arrCustomer.Add(cCust);
}
private void btnExit_Click(object sender, System.EventArgs e)
{
this.Close();
}
private void btnAdd_Click(object sender, EventArgs e)
{
txtFirst.DataBindings.Add(
txtLast.DataBindings.Add("
txtAddress.DataBindings.Ad
}
private void btnInc_Click(object sender, EventArgs e)
{
if (this.BindingContext[arrCu
this.BindingContext[arrCus
else
this.BindingContext[arrCus
}
private void btnChange_Click(object sender, EventArgs e)
{
((clsCustomer)arrCustomer[
}
}
public class clsCustomer : INotifyPropertyChanged
{
private string _strFirst = "";
private string _strLast = "";
private string _strAddress = "";
public string strFirst
{
get
{
return _strFirst;
}
set
{
_strFirst = value;
PropertyChangedNotify("str
}
}
public string strLast
{
get
{
return _strLast;
}
set
{
_strLast = value;
PropertyChangedNotify("str
}
}
public string strAddress
{
get
{
return _strAddress;
}
set
{
_strAddress = value;
PropertyChangedNotify("str
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandle
private void PropertyChangedNotify(stri
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(s
}
}
#endregion
}
}
Oh... I'm sorry... of course it's bind.ReadValue() instead of writeValue. You want the bindingpartners to read the value. not to write their value
ASKER
Quote:
"The problem is simply, that the graphic Elements do not know that you've changed the value behind."
But isn't that what implementing INotifyPropertyChanged is for? By implementing this the way I did, anything that is bound to a customer object should automatically know that it has been changed, right? Every time one of the properties is changed the propertychanged event is raised (see the clsCustomer class).
I see that the following code works:
((clsCustomer)arrCustomer[ 0]).strAdd ress = "Changed address";
foreach (Binding bind in txtAddress.DataBindings)
{
bind.ReadValue();
}
But it seems very tedious to have to call the 'foreach' loop after every time I've changed any variable in code. There must be a better way to do this. Isn't there a way to set up my the data binding to where it would just automatically update all associated bindings if I changed the property in code? it seems like there has to be since when a clsCustomer object property is changed, the clsCustomer object is broadcasting the change through the 'propertychanged' event.
Thanks
"The problem is simply, that the graphic Elements do not know that you've changed the value behind."
But isn't that what implementing INotifyPropertyChanged is for? By implementing this the way I did, anything that is bound to a customer object should automatically know that it has been changed, right? Every time one of the properties is changed the propertychanged event is raised (see the clsCustomer class).
I see that the following code works:
((clsCustomer)arrCustomer[
foreach (Binding bind in txtAddress.DataBindings)
{
bind.ReadValue();
}
But it seems very tedious to have to call the 'foreach' loop after every time I've changed any variable in code. There must be a better way to do this. Isn't there a way to set up my the data binding to where it would just automatically update all associated bindings if I changed the property in code? it seems like there has to be since when a clsCustomer object property is changed, the clsCustomer object is broadcasting the change through the 'propertychanged' event.
Thanks
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thank you! You were right the answer was in that document. The problem was I needed to add a binding source to be in-between the control and the arrayList data source. This is because ArrayList does not implement IBindingList, and any list which will update correctly like that needs to implement IBindingList.
Here is the new code:
private void btnAdd_Click(object sender, EventArgs e)
{
bs = new BindingSource();
bs.DataSource = arrCustomer;
txtFirst.DataBindings.Add( "Text", bs, "strFirst");
txtLast.DataBindings.Add(" Text", bs, "strLast");
txtAddress.DataBindings.Ad d("Text", bs, "strAddress");
}
private void btnInc_Click(object sender, EventArgs e)
{
if (this.BindingContext[bs].P osition >= bs.Count - 1)
this.BindingContext[bs].Po sition = 0;
else
this.BindingContext[bs].Po sition++;
}
private void btnChange_Click(object sender, EventArgs e)
{
((clsCustomer)arrCustomer[ 0]).strAdd ress = "Changed address";
//here is just a test to make sure the binding still works
// when editing the ArrayList. It does.
clsCustomer cCust = new clsCustomer();
cCust.strFirst = "11";
cCust.strLast = "22";
cCust.strAddress = "333";
//arrCustomer.Add(cCust);
bs.Add(cCust); //although the above commented out line works, when using a binding
//source you're supposed to interact with the data through
// it now instead of the original list (see msdn)
}
Here is the new code:
private void btnAdd_Click(object sender, EventArgs e)
{
bs = new BindingSource();
bs.DataSource = arrCustomer;
txtFirst.DataBindings.Add(
txtLast.DataBindings.Add("
txtAddress.DataBindings.Ad
}
private void btnInc_Click(object sender, EventArgs e)
{
if (this.BindingContext[bs].P
this.BindingContext[bs].Po
else
this.BindingContext[bs].Po
}
private void btnChange_Click(object sender, EventArgs e)
{
((clsCustomer)arrCustomer[
//here is just a test to make sure the binding still works
// when editing the ArrayList. It does.
clsCustomer cCust = new clsCustomer();
cCust.strFirst = "11";
cCust.strLast = "22";
cCust.strAddress = "333";
//arrCustomer.Add(cCust);
bs.Add(cCust); //although the above commented out line works, when using a binding
//source you're supposed to interact with the data through
// it now instead of the original list (see msdn)
}
foreach(System.Windows.For
if(bind
try
{
bind.WriteValue();
}
catch{} // Error
By this you say the form to update! Hope this would help
best regards