Data binding controls to custom objects

I have an object called Customer. It is not a data row, but instead is derived from MarshalByRefObject. Properties of this object are bound to controls on a Windows Form for editing.

The problem I have is that changes to the values made on the screen are not reflected in the object, and changes to the object are not reflected on the screen. The correct values show up on window initialization, as the properties are populated at the time of binding, but any changes after binding are ineffectual.

I really appreciate any help.

Here's code with an example of the problem. You can see the presentation and function of the first text box (from a DataTable) is correct, while the second is not. What am I doing wrong?

Tom

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace TestBed
{
/// <summary>
/// Summary description for DataBindingTest.
/// </summary>
public class DataBindingTest : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox textBox1;
private System.ComponentModel.Container components = null;
private System.Windows.Forms.Button button1;
private BindMe binder = new BindMe ();
private System.Windows.Forms.TextBox textBox2;
private DataTable dt = new DataTable ("Customer");

public DataBindingTest()
{
InitializeComponent();
dt.Columns.Add ("Test");
dt.Rows.Add (new object[] {"XXX"});
this.textBox1.DataBindings.Add (new Binding ("Text", dt, "Test"));
this.textBox2.DataBindings.Add (new Binding ("Text", binder, "Value"));
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.textBox2 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(48, 16);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(304, 20);
this.textBox1.TabIndex = 0;
this.textBox1.Text = "textBox1";
//
// button1
//
this.button1.Location = new System.Drawing.Point(40, 112);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(152, 24);
this.button1.TabIndex = 1;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(48, 40);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(304, 20);
this.textBox2.TabIndex = 2;
this.textBox2.Text = "textBox2";
//
// DataBindingTest
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(472, 317);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.button1);
this.Controls.Add(this.textBox1);
this.Name = "DataBindingTest";
this.Text = "DataBindingTest";
this.ResumeLayout(false);

}
#endregion

private void button1_Click(object sender, System.EventArgs e)
{
dt.Rows[0]["Test"] = "YYY";
binder.Value = "YYY";
this.Update();
}
}
public class BindMe : MarshalByRefObject
{
string myValue = "XXX";
public BindMe()
{
}
public string Value
{
get {return myValue;}
set {myValue = value;}
}
}
}

[4203 byte] By [codefund.com] at [2007-12-16]
# 1
Hi Tom,

The problem is that your BindMe class does not support two-way binding. Two-way binding is typically accomplished using a DataSet, but that may be overkill in some situations.

The <a href="http://www.syncfusion.com/FAQ/WinForms/FAQ_c43c.asp#q757q">Windows Forms FAQ</a> discusses this problem as it relates to an ArrayList, where you can reset the datasource or refresh the binding through its CurrencyManager. This won't work in your simple binding example, however, in which the binding is managed with a PropertyManager instead of a CurrencyManager. One thing that seems to work is to suspend the binding and resume it after the change has been made:

private void button1_Click(object sender, System.EventArgs e)
{
BindingManagerBase bm = this.textBox2.BindingContext[binder];
bm.SuspendBinding();

dt.Rows[0]["Test"] = "YYY";
binder.Value = "YYY";
this.Update();

bm.ResumeBinding();
}

I hope this helps.

-Karl Erickson

codefund.com at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 2
Karl,

Thanks for your help. That seems a little cumbersome for a large editing job, but such is life :)

Thanks again.

Tom

codefund.com at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...