Microsoft KB Archive/812918

= FIX: Data Bound User Control Updates Only First Bound Column =

Article ID: 812918

Article Last Modified on 1/22/2004

-

APPLIES TO


 * Microsoft ADO.NET 1.0
 * Microsoft Visual Basic .NET 2002 Standard Edition
 * Microsoft Visual C# .NET 2002 Standard Edition

-



SYMPTOMS
When you try to update more than one column of a table by using a bound user control that has multiple bound properties, only the modified data for the first bound property is updated in the table. You may notice this behavior only for the first row of the table.



WORKAROUND
To work around this problem in ADO.NET 1.0, call EndCurrentEdit to end the current edit operation for all the bound controls. You can call EndCurrentEdit in the Validating event of each bound control, or you can call the OnValidating event of the UserControl class as demonstrated in the following code:

Call EndCurrentEdit in the Validate Event of UserControl
Append the following code to the UserControl1 class:

Visual Basic .NET Code
' Override the OnValidating of a Control Protected Overrides Sub OnValidating(ByVal e As System.ComponentModel.CancelEventArgs) ' Iterate through each bound object and then end the current edit Dim b As Binding For Each b In Me.DataBindings Dim cm As CurrencyManager = b.BindingManagerBase cm.EndCurrentEdit Next End Sub

Visual C# .NET Code
// Override the OnValidating of a Control protected override void OnValidating(CancelEventArgs e)    { // Iterate through each bound object and then end the current edit foreach (Binding b in this.DataBindings) {           CurrencyManager cm =(CurrencyManager)(b.BindingManagerBase); cm.EndCurrentEdit; }    }

Call EndCurrentEdit in the Validating Event of Each Control That Is Used in UserControl
Add the following code to the Validating event of the control that is used in the UserControl class. For example, when you use a TextBox control in your UserControl class, add the following Validating event code for the TextBox1 control:

Visual Basic .NET Code
' Validating event of First control Private Sub TextBox1_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating m_Property1 = TextBox1.Text OnValidating(e) ' Iterate through each bound object and then end the current edit Dim b As Binding For Each b In Me.DataBindings Dim cm As CurrencyManager = b.BindingManagerBase cm.EndCurrentEdit Next End Sub

Protected Overrides Sub OnValidating(ByVal e As System.ComponentModel.CancelEventArgs) End Sub

Visual C# .NET Code
// Validating event of First control private void textBox1_Validating(object sender, System.ComponentModel.CancelEventArgs e)     { m_Property1= textBox1.Text; OnValidating(e); foreach (Binding b in this.DataBindings) {           CurrencyManager cm =(CurrencyManager)(b.BindingManagerBase); cm.EndCurrentEdit; }     }

protected override void OnValidating(CancelEventArgs e)     { }



STATUS
Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article. This bug was corrected in ADO.NET version 1.1 for data binding.



Steps to Reproduce the Behavior
 Create a new Windows Control Library project by using Microsoft Visual C# .NET or Microsoft Visual Basic .NET. Name the Project MyUserControl. By default, UserControl1 is created. Drag two TextBox controls from the Toolbox to UserControl1. TextBox1 and TextBox2 are created. In Solution Explorer, right-click UserControl1, and then click View Code.  Replace the existing code with the following code:

Visual Basic .NET
Public Class UserControl1 Inherits System.Windows.Forms.UserControl


 * 1) Region &quot; Windows Form Designer generated code &quot;

Public Sub New MyBase.New InitializeComponent End Sub

'UserControl1 overrides dispose to clean up the component list. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose End If     End If      MyBase.Dispose(disposing) End Sub

'Required by the Windows Form Designer Private components As System.ComponentModel.IContainer

Friend WithEvents TextBox1 As System.Windows.Forms.TextBox Friend WithEvents TextBox2 As System.Windows.Forms.TextBox  Private Sub InitializeComponent Me.TextBox1 = New System.Windows.Forms.TextBox Me.TextBox2 = New System.Windows.Forms.TextBox Me.SuspendLayout 'TextBox1 Me.TextBox1.Location = New System.Drawing.Point(8, 8) Me.TextBox1.Name = &quot;TextBox1&quot; Me.TextBox1.Size = New System.Drawing.Size(96, 20) Me.TextBox1.TabIndex = 0 Me.TextBox1.Text = &quot;&quot; 'TextBox2 Me.TextBox2.Location = New System.Drawing.Point(112, 8) Me.TextBox2.Name = &quot;TextBox2&quot; Me.TextBox2.Size = New System.Drawing.Size(96, 20) Me.TextBox2.TabIndex = 1 Me.TextBox2.Text = &quot;&quot; 'UserControl1 Me.BackColor = System.Drawing.SystemColors.ActiveCaption Me.Controls.AddRange(New System.Windows.Forms.Control {Me.TextBox2, Me.TextBox1}) Me.Name = &quot;UserControl1&quot; Me.Size = New System.Drawing.Size(216, 40) Me.ResumeLayout(False)

End Sub


 * 1) End Region

' Public Properties Private m_Property1 As String Private m_Property2 As String

Public Property Property1 As String Get Return m_Property1 End Get Set(ByVal Value As String) m_Property1 = Value TextBox1.Text = m_Property1 End Set End Property

Public Property Property2 As String Get Return m_Property2 End Get Set(ByVal Value As String) m_Property2 = Value TextBox2.Text = m_Property2 End Set End Property

' Set the value in the TextBox1 to Property1 Private Sub TextBox1_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating m_Property1 = TextBox1.Text End Sub

' Set the value in the TextBox2 to Property2 Private Sub TextBox2_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox2.Validating m_Property2 = TextBox2.Text End Sub

End Class

Visual C# .NET
using System; using System.Collections; using System.ComponentModel; using System.Drawing; using System.Data; using System.Windows.Forms;

namespace MyUserControl {   public class UserControl1 : System.Windows.Forms.UserControl {     private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.TextBox textBox2; private System.ComponentModel.Container components = null;

public UserControl1 {           // This call is required by the Windows.Forms Form Designer. InitializeComponent;

// TODO: Add any initialization after the InitForm call

}

protected override void Dispose( bool disposing ) {           if( disposing ) {               if( components != null ) components.Dispose; }           base.Dispose( disposing ); }   #region Component Designer generated code private void InitializeComponent {        this.textBox1 = new System.Windows.Forms.TextBox; this.textBox2 = new System.Windows.Forms.TextBox; this.SuspendLayout; // textBox1 this.textBox1.Location = new System.Drawing.Point(8, 8); this.textBox1.Name = &quot;textBox1&quot;; this.textBox1.Size = new System.Drawing.Size(88, 20); this.textBox1.TabIndex = 0; this.textBox1.Text = &quot;&quot;; this.textBox1.Validating += new System.ComponentModel.CancelEventHandler(this.textBox1_Validating); // textBox2 this.textBox2.Location = new System.Drawing.Point(104, 8); this.textBox2.Name = &quot;textBox2&quot;; this.textBox2.Size = new System.Drawing.Size(88, 20); this.textBox2.TabIndex = 1; this.textBox2.Text = &quot;&quot;; this.textBox2.Validating += new System.ComponentModel.CancelEventHandler(this.textBox2_Validating); // UserControl1 this.BackColor = System.Drawing.SystemColors.ActiveCaption; this.Controls.AddRange(new System.Windows.Forms.Control[] {                                                                     this.textBox2,                                                                      this.textBox1}); this.Name = &quot;UserControl1&quot;; this.Size = new System.Drawing.Size(200, 40); this.ResumeLayout(false);

}

#endregion // Public Properties private string m_Property1; private string m_Property2;

public string Property1 {        get {           return m_Property1; }        set {           m_Property1 = value; textBox1.Text = m_Property1; }     }

public string Property2 {        get {           return m_Property2; }        set {           m_Property2 = value; textBox2.Text = m_Property2; }     }

// Set the value in the TextBox1 to Property1 private void textBox1_Validating(object sender, System.ComponentModel.CancelEventArgs e)     { m_Property1 = textBox1.Text; }

// Set the value in the TextBox2 to Property2 private void textBox2_Validating(object sender, System.ComponentModel.CancelEventArgs e)     { m_Property2 = textBox2.Text; } } }  On the Build menu, click Build Solution. On the File menu, point to Add Project, and then click New Project.</li> Under Project Type, click Visual Basic Projects or Visual C# Projects.</li> Under Templates, click Windows Application, and then click OK.</li> In Solution Explorer, right-click the Windows Application project name, and then click Set as StartUp Project.</li> Drag the UserControl (that you created in step 5) from the Toolbox to Form1.</li> Drag a DataGrid control from the Toolbox to Form1.</li> In Design View, double-click Form1 to add code to the Load event of the Form1.</li>  Replace the Form_Load event code with the following code:

Visual Basic .NET Code
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim dt As DataTable ' Create a Datasource dt = New DataTable(&quot;Student&quot;) dt.Columns.Add(&quot;StudentName&quot;, Type.GetType(&quot;System.String&quot;)) dt.Columns.Add(&quot;Age&quot;, Type.GetType(&quot;System.String&quot;))

' Add data to the table Dim dr As DataRow = dt.NewRow dr(&quot;StudentName&quot;) = &quot;Robert&quot; dr(&quot;Age&quot;) = &quot;15&quot; dt.Rows.Add(dr)

dr = dt.NewRow dr(&quot;StudentName&quot;) = &quot;Mike&quot; dr(&quot;Age&quot;) = &quot;12&quot; dt.Rows.Add(dr)

dr = dt.NewRow dr(&quot;StudentName&quot;) = &quot;Bob&quot; dr(&quot;Age&quot;) = &quot;14&quot; dt.Rows.Add(dr)

UserControl11.DataBindings.Add(&quot;Property1&quot;, dt, &quot;StudentName&quot;) UserControl11.DataBindings.Add(&quot;Property2&quot;, dt, &quot;Age&quot;)

DataGrid1.DataSource = dt  End Sub

Visual C# .NET Code
private void Form1_Load(object sender, System.EventArgs e)     { DataTable dt; // Create a Datasource dt = new DataTable(&quot;Student&quot;); dt.Columns.Add(&quot;StudentName&quot;, Type.GetType(&quot;System.String&quot;)); dt.Columns.Add(&quot;Age&quot;, Type.GetType(&quot;System.String&quot;)); // Add data to the table DataRow dr = dt.NewRow; dr[&quot;StudentName&quot;] = &quot;Robert&quot;; dr[&quot;Age&quot;] = &quot;15&quot;; dt.Rows.Add(dr);

dr = dt.NewRow; dr[&quot;StudentName&quot;] = &quot;Mike&quot;; dr[&quot;Age&quot;] = &quot;12&quot;; dt.Rows.Add(dr);

dr = dt.NewRow; dr[&quot;StudentName&quot;] = &quot;Bob&quot;; dr[&quot;Age&quot;] = &quot;14&quot;; dt.Rows.Add(dr);

userControl11.DataBindings.Add(&quot;Property1&quot;, dt, &quot;StudentName&quot;); userControl11.DataBindings.Add(&quot;Property2&quot;, dt, &quot;Age&quot;);

dataGrid1.DataSource = dt; } </li> On the Debug menu, click Start to run the application. In the UserControl, the StudentName is displayed as &quot;Robert&quot; and Age as &quot;15&quot;. The DataGrid displays the data in the DataTable.</li> Change the StudentName in the UserControl to &quot;Thomas&quot; and the Age to &quot;20&quot;.</li> Press ENTER. Verify that the StudentName in the DataGrid is modified but the Age is not.</li></ol>

<div class="references_section">