.NET Framework - Two-way binding using DataSourceUpdateMode.OnPropertyChanged does not work

Asked By Tony Johansson on 13-Mar-11 06:35 AM
Hello!

This two-way binding works in one project but not in the other despide using
this DataSourceUpdateMode.OnPropertyChanged.
The only difference between these two project is that in one we have a
simple TextBox and in the other we have a user control where we use the
TextBox in this user control.

In the project where two way binding works I have this code see below and as
you can see I just changed this row
textBox.DataBindings.Add("Text", thisPlayer, "Name");
to this row
textBox.DataBindings.Add("Text", thisPlayer, "Name",true,
DataSourceUpdateMode.OnPropertyChanged);
So here I enter a name in a DataGridView cell push the enter key and the
name is displayed in the TextBox. Now I can change the name in the TextBox
and push the enter key and the name is changed in the DataGridView cell.

Now in the project where I have a user control that contains several control
but one of these is a TextBox.
Now it works perfect in one directions so if I enter a name in a
DataGridView cell and push the enter key this name is displayed in the user
control TextBox if I now change this name in the user control this name is
not change in the DataGridView cell but if I just click in the corresponding
cell in the DataGridView the name is updated to match what I wrote in the
user control.
All code for the binding is listed.
So my question is why does it not work in both directions when I use a user
control ?


// This code is for the project where two way binding works
//*********************************************
private void dataGridView1_CellValueChanged(object sender,
DataGridViewCellEventArgs e)
{
if (textBox == null)
return;

Player thisPlayer = players[e.RowIndex];

foreach (TextBox tb in textBoxes)
{
if (tb.Text == thisPlayer.Name)
{
tb.DataBindings.Remove(tb.DataBindings["Text"]);
textBox = tb;
break;
}
}
textBox.DataBindings.Add("Text", thisPlayer, "Name",true,
DataSourceUpdateMode.OnPropertyChanged);
}


// This code is for the project where two way binding does not work
//*************************************************
private void dgvAllPlayers_CellValueChanged(object sender,
DataGridViewCellEventArgs e)
{
if (pg != null)
{
Player thisPlayer = gameManager.Players[e.RowIndex];

foreach (PlayerGUI pGUI in gameManager.PlayerGUIs)
{
if (pGUI.Namn == thisPlayer.Name)
{
pGUI.DataBindings.Remove(pGUI.DataBindings["Namn"]);
pg = pGUI;

if (string.Equals(thisPlayer.Name, Croupier,
StringComparison.CurrentCultureIgnoreCase))
BtnStartGame.Enabled = true;

break;
}
}

if (gameManager.Players.Count <= gameManager.PlayerGUIs.Count)
pg.DataBindings.Add("Namn", thisPlayer, "Name", true,
DataSourceUpdateMode.OnPropertyChanged);
}
}

//Tony




Tony Johansson replied to Tony Johansson on 13-Mar-11 06:52 AM
Forget this mail I must check more

//Tony
Tony Johansson replied to Tony Johansson on 13-Mar-11 07:21 AM
Hello!

A complete example where binding works in one directions only.
I have a DataGridView and when I click on the event handler
BtnCreateTextBox_Click a new TextBox is created.
and now I enter a name in the DataGridView cell and click enter and the name
is displayed in the TextBox which is perfect.
Now I do the same with three TextBoxes so I have three rows in the
datagridView which have the namnes
aaa
bbb
ccc
and each of these namnes is displayed in each TextBox.
Now I place the cursor on the last row in the DataGridView and change the
name aaa to 111 in the TextBox and change focus to the TextBox where the
name is bbb. The is no change at all in the DataGridView cell aaa. Now I
change bbb in the TextBox to 222 and change focus to the last textBox where
ccc is displayed and again no change at all in the dataGridView.
Now I change ccc in the TextBox to 333 and now I can see that ccc in the
DataGridView is changed to 333 because
the cursor was placed in this cell.

So why does it not work in both direction ?
I use this binding statement
textBox.DataBindings.Add("Text", thisPlayer, "Name",true,
DataSourceUpdateMode.OnPropertyChanged);
which should cause binding to work in both directions.



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Testing
{
public partial class Form1 : Form
{
private int xpos = 0;
private int ypos = 0;
private BindingSource bindingSource = new BindingSource();
private List<Player> players = new List<Player>();
private TextBox textBox;

private List<TextBox> textBoxes = new List<TextBox>();

public Form1()
{
InitializeComponent();
bindingSource.DataSource = players;
dataGridView1.DataSource = bindingSource;
}

private void BtnCreateTextBox_Click(object sender, EventArgs e)
{
textBox = new TextBox();
textBoxes.Add(textBox);

textBox.Location = new Point(xpos += 20, ypos += 20);
panel1.Controls.Add(textBox);
}

private void dataGridView1_CellValueChanged(object sender,
DataGridViewCellEventArgs e)
{
if (textBox == null)
return;

Player thisPlayer = players[e.RowIndex];

foreach (TextBox tb in textBoxes)
{
if (tb.Text == thisPlayer.Name)
{
tb.DataBindings.Remove(tb.DataBindings["Text"]);
textBox = tb;
break;
}
}
textBox.DataBindings.Add("Text", thisPlayer, "Name",true,
DataSourceUpdateMode.OnPropertyChanged);
}
}

public class Player
{
private int playerID;
private string name;

public Player(int ID, string name)
{
this.playerID = ID;
this.name = name;
}

public Player()
{}

public string Name
{
get { return name; }
set { name = value; }
}

public int PlayerID
{
get { return playerID; }
set { playerID = value; }
}
}

//A copy paste from Form1.Designer.cs
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// true if managed resources should be
disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
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.dataGridView1 = new System.Windows.Forms.DataGridView();
this.BtnCreateTextBox = new System.Windows.Forms.Button();
this.panel1 = new System.Windows.Forms.Panel();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// dataGridView1
//
this.dataGridView1.ColumnHeadersHeightSizeMode =
System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Location = new System.Drawing.Point(12, 137);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.Size = new System.Drawing.Size(267, 121);
this.dataGridView1.TabIndex = 0;
this.dataGridView1.CellValueChanged += new
System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellValueChanged);
//
// BtnCreateTextBox
//
this.BtnCreateTextBox.Location = new System.Drawing.Point(285,
167);
this.BtnCreateTextBox.Name = "BtnCreateTextBox";
this.BtnCreateTextBox.Size = new System.Drawing.Size(153, 23);
this.BtnCreateTextBox.TabIndex = 1;
this.BtnCreateTextBox.Text = "CreateTextBox";
this.BtnCreateTextBox.UseVisualStyleBackColor = true;
this.BtnCreateTextBox.Click += new
System.EventHandler(this.BtnCreateTextBox_Click);
//
// panel1
//
this.panel1.Location = new System.Drawing.Point(12, 12);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(405, 108);
this.panel1.TabIndex = 2;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(444, 270);
this.Controls.Add(this.panel1);
this.Controls.Add(this.BtnCreateTextBox);
this.Controls.Add(this.dataGridView1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);

}


private System.Windows.Forms.DataGridView dataGridView1;
private System.Windows.Forms.Button BtnCreateTextBox;
private System.Windows.Forms.Panel panel1;
}
}

//Tony