Solved

simple data binding not working - ArrayList of Customer objects to textbox's

Posted on 2007-03-21
5
322 Views
Last Modified: 2013-11-07
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.Add("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]).strAddress = "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.RegularExpressions;

namespace dnUtil
{
      public class Form1 : System.Windows.Forms.Form
      {
            #region Windows Form Designer generated code

        public System.Windows.Forms.Button btnInc;
        public System.Windows.Forms.Button btnAdd;
        private dnUtil.Controls.TextBoxDroppable txtFirst;
        private dnUtil.Controls.TextBoxDroppable txtLast;
        private dnUtil.Controls.TextBoxDroppable txtAddress;
        private Label txtStatus;
        public Button btnChange;
        public System.Windows.Forms.Button 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.Button();
            this.btnAdd = new System.Windows.Forms.Button();
            this.btnExit = new System.Windows.Forms.Button();
            this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog();
            this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
            this.txtStatus = new System.Windows.Forms.Label();
            this.btnChange = new System.Windows.Forms.Button();
            this.txtAddress = new dnUtil.Controls.TextBoxDroppable();
            this.txtLast = new dnUtil.Controls.TextBoxDroppable();
            this.txtFirst = new dnUtil.Controls.TextBoxDroppable();
            this.SuspendLayout();
            //
            // btnInc
            //
            this.btnInc.BackColor = System.Drawing.SystemColors.Control;
            this.btnInc.Cursor = System.Windows.Forms.Cursors.Default;
            this.btnInc.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.btnInc.ForeColor = System.Drawing.SystemColors.ControlText;
            this.btnInc.Location = new System.Drawing.Point(266, 79);
            this.btnInc.Name = "btnInc";
            this.btnInc.RightToLeft = System.Windows.Forms.RightToLeft.No;
            this.btnInc.Size = new System.Drawing.Size(105, 24);
            this.btnInc.TabIndex = 33;
            this.btnInc.Text = "Increment Binding";
            this.btnInc.UseVisualStyleBackColor = false;
            this.btnInc.Click += new System.EventHandler(this.btnInc_Click);
            //
            // btnAdd
            //
            this.btnAdd.BackColor = System.Drawing.SystemColors.Control;
            this.btnAdd.Cursor = System.Windows.Forms.Cursors.Default;
            this.btnAdd.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.btnAdd.ForeColor = System.Drawing.SystemColors.ControlText;
            this.btnAdd.Location = new System.Drawing.Point(266, 6);
            this.btnAdd.Name = "btnAdd";
            this.btnAdd.RightToLeft = System.Windows.Forms.RightToLeft.No;
            this.btnAdd.Size = new System.Drawing.Size(105, 24);
            this.btnAdd.TabIndex = 32;
            this.btnAdd.Text = "Add Binding";
            this.btnAdd.UseVisualStyleBackColor = false;
            this.btnAdd.Click += new System.EventHandler(this.btnAdd_Click);
            //
            // btnExit
            //
            this.btnExit.BackColor = System.Drawing.SystemColors.Control;
            this.btnExit.Cursor = System.Windows.Forms.Cursors.Default;
            this.btnExit.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.btnExit.ForeColor = System.Drawing.SystemColors.ControlText;
            this.btnExit.Location = new System.Drawing.Point(298, 109);
            this.btnExit.Name = "btnExit";
            this.btnExit.RightToLeft = System.Windows.Forms.RightToLeft.No;
            this.btnExit.Size = new System.Drawing.Size(73, 24);
            this.btnExit.TabIndex = 31;
            this.btnExit.Text = "E&xit";
            this.btnExit.UseVisualStyleBackColor = false;
            this.btnExit.Click += new System.EventHandler(this.btnExit_Click);
            //
            // 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.SystemColors.Control;
            this.btnChange.Cursor = System.Windows.Forms.Cursors.Default;
            this.btnChange.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.btnChange.ForeColor = System.Drawing.SystemColors.ControlText;
            this.btnChange.Location = new System.Drawing.Point(266, 36);
            this.btnChange.Name = "btnChange";
            this.btnChange.RightToLeft = System.Windows.Forms.RightToLeft.No;
            this.btnChange.Size = new System.Drawing.Size(105, 24);
            this.btnChange.TabIndex = 47;
            this.btnChange.Text = "Change Address";
            this.btnChange.UseVisualStyleBackColor = false;
            this.btnChange.Click += new System.EventHandler(this.btnChange_Click);
            //
            // 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.btnChange);
            this.Controls.Add(this.txtStatus);
            this.Controls.Add(this.txtAddress);
            this.Controls.Add(this.txtLast);
            this.Controls.Add(this.txtFirst);
            this.Controls.Add(this.btnInc);
            this.Controls.Add(this.btnAdd);
            this.Controls.Add(this.btnExit);
            this.Name = "Form1";
            this.Text = "BindingTest (1.0.0)";
            this.Load += new System.EventHandler(this.Form1_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.Add("Text", arrCustomer, "strAddress");
        }

        private void btnInc_Click(object sender, EventArgs e)
        {
            if (this.BindingContext[arrCustomer].Position > 0)
                this.BindingContext[arrCustomer].Position = 0;
            else
                this.BindingContext[arrCustomer].Position++;
        }

        private void btnChange_Click(object sender, EventArgs e)
        {
            ((clsCustomer)arrCustomer[0]).strAddress = "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("strFirst");
            }
        }

        public string strLast
        {
            get
            {
                return _strLast;
            }
            set
            {
                _strLast = value;
                PropertyChangedNotify("strLast");
            }
        }

        public string strAddress
        {
            get
            {
                return _strAddress;
            }
            set
            {
                _strAddress = value;
                PropertyChangedNotify("strAddress");
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void PropertyChangedNotify(string strProperty)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(strProperty));
            }
        }

        #endregion

    }

}
0
Comment
Question by:prosh0t
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
5 Comments
 
LVL 2

Expert Comment

by:_Eyeball_
ID: 18767180
I think i can imagine your problem. The problem is simply, that the graphic Elements do not know that you've changed the value behind. You have to save the bindings in the clsCustomer class an do, every time the parameter changed (set) something like this.

foreach(System.Windows.Forms.Binding bind in this.m_Bindingstore)
if(bind
try
{
bind.WriteValue();
}
catch{} // Error

By this you say the form to update! Hope this would help

best regards
0
 
LVL 2

Expert Comment

by:_Eyeball_
ID: 18767204
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
0
 
LVL 7

Author Comment

by:prosh0t
ID: 18767390
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]).strAddress = "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
0
 
LVL 2

Accepted Solution

by:
_Eyeball_ earned 500 total points
ID: 18769451
ok. first of all a very usefull paper about databinding is this one (www.windowsforms.net/Samples/Go%20To%20Market/Data%20Binding/DataBinding%20FAQ.doc)

I debugged your code an see that the databinding event is null. i think thats because you use a complex dababinding which differentiate from the simple one. when you add only a clscustomer it works correctly. if you want that the text changes, when you enter a text directly into the textbox you have to do the following:

 txtFirst.DataBindings.Add("Text", temp, "strFirst",true, DataSourceUpdateMode.OnPropertyChanged);
            txtLast.DataBindings.Add("Text", temp, "strLast", true, DataSourceUpdateMode.OnPropertyChanged);
            txtAddress.DataBindings.Add("Text", temp, "strAddress", true, DataSourceUpdateMode.OnPropertyChanged);

The solution for: "how do i do update in complex databinding" you should find under the link i've gave to you

best regards
0
 
LVL 7

Author Comment

by:prosh0t
ID: 18772423
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.Add("Text", bs, "strAddress");
}

private void btnInc_Click(object sender, EventArgs e)
{
    if (this.BindingContext[bs].Position >= bs.Count - 1)
        this.BindingContext[bs].Position = 0;
    else
        this.BindingContext[bs].Position++;
}

private void btnChange_Click(object sender, EventArgs e)
{
    ((clsCustomer)arrCustomer[0]).strAddress = "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)
}

0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
VB.net/VSTO Excel Add-in 2 38
array not updating 8 42
PowerShell: ForEach-Object Export to CSV 4 92
SSIS Column mapping 5 41
For those of you who don't follow the news, or just happen to live under rocks, Microsoft Research released a beta SDK (http://www.microsoft.com/en-us/download/details.aspx?id=27876) for the Xbox 360 Kinect. If you don't know what a Kinect is (http:…
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

739 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question