none
User control with multiple bindable properties updates only the last changed field

    Question

  • Hello everybody,

    I am trying to make a custom reusable control which will be editing the address fields of my custom entities (for example my contacts may have 2 addresses, one for home and one for bussiness). This control contains 4 textboxes (AddressTextBox, PostCodeTextBox, AreaRegionTextBox and CityTextBox) and provides 4 properties to expose the corresponding value (Address, PostCode, AreaRegion and City).

    My entity (which implements the INotifyPropertyChanged interface) is the following:

    Imports System.ComponentModel
    
    
    
    
    
    
    
    Public Class Person
    
    
    
     Implements INotifyPropertyChanged
    
    
    
    
    
    
    
     Private _fldLastName As String = String.Empty
    
    
    
     Public Property fldLastName() As System.String
    
    
    
     Get
    
    
    
      Return _fldLastName
    
    
    
     End Get
    
    
    
     Set(ByVal value As System.String)
    
    
    
      If Not _fldLastName.Equals(value) Then
    
    
    
      _fldLastName = value
    
    
    
      RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("fldLastName"))
    
    
    
      End If
    
    
    
     End Set
    
    
    
     End Property
    
    
    
    
    
    
    
     Private _fldFirstName As String = String.Empty
    
    
    
     Public Property fldFirstName() As System.String
    
    
    
     Get
    
    
    
      Return _fldFirstName
    
    
    
     End Get
    
    
    
     Set(ByVal value As System.String)
    
    
    
      If Not _fldFirstName.Equals(value) Then
    
    
    
      _fldFirstName = value
    
    
    
      RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("fldFirstName"))
    
    
    
      End If
    
    
    
     End Set
    
    
    
     End Property
    
    
    
    
    
    
    
     Private _fldAddress As String = String.Empty
    
    
    
     Public Property fldAddress() As System.String
    
    
    
     Get
    
    
    
      Return _fldAddress
    
    
    
     End Get
    
    
    
     Set(ByVal value As System.String)
    
    
    
      If Not _fldAddress.Equals(value) Then
    
    
    
      _fldAddress = value
    
    
    
      RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("fldAddress"))
    
    
    
      End If
    
    
    
     End Set
    
    
    
     End Property
    
    
    
     Private _fldPostCode As String = String.Empty
    
    
    
     Public Property fldPostCode() As System.String
    
    
    
     Get
    
    
    
      Return _fldPostCode
    
    
    
     End Get
    
    
    
     Set(ByVal value As System.String)
    
    
    
      If Not _fldPostCode.Equals(value) Then
    
    
    
      _fldPostCode = value
    
    
    
      RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("fldPostCode"))
    
    
    
      End If
    
    
    
     End Set
    
    
    
     End Property
    
    
    
    
    
    
    
     Private _fldRegion As String = String.Empty
    
    
    
     Public Property fldRegion() As System.String
    
    
    
     Get
    
    
    
      Return _fldRegion
    
    
    
     End Get
    
    
    
     Set(ByVal value As System.String)
    
    
    
      If Not _fldRegion.Equals(value) Then
    
    
    
      _fldRegion = value
    
    
    
      RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("fldRegion"))
    
    
    
      End If
    
    
    
     End Set
    
    
    
     End Property
    
    
    
    
    
    
    
     Private _fldCity As String = String.Empty
    
    
    
     Public Property fldCity() As System.String
    
    
    
     Get
    
    
    
      Return _fldCity
    
    
    
     End Get
    
    
    
     Set(ByVal value As System.String)
    
    
    
      If Not _fldCity.Equals(value) Then
    
    
    
      _fldCity = value
    
    
    
      RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("fldCity"))
    
    
    
      End If
    
    
    
     End Set
    
    
    
     End Property
    
    
    
    
    
    
    
     Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
    
    
    
    End Class
    
    
    
    
    
    
    
    

    The custom Address control is named cntAddress.vb and the designer code is the following:

    Partial Class cntAddress
    
    
    
     Inherits System.Windows.Forms.UserControl
    
    
    
    
    
    
    
     'UserControl overrides dispose to clean up the component list.
    
    
    
     <System.Diagnostics.DebuggerNonUserCode()> _
    
    
    
     Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    
    
    
     Try
    
    
    
      If disposing AndAlso components IsNot Nothing Then
    
    
    
      components.Dispose()
    
    
    
      End If
    
    
    
     Finally
    
    
    
      MyBase.Dispose(disposing)
    
    
    
     End Try
    
    
    
     End Sub
    
    
    
    
    
    
    
     'Required by the Windows Form Designer
    
    
    
     Private components As System.ComponentModel.IContainer
    
    
    
    
    
    
    
     'NOTE: The following procedure is required by the Windows Form Designer
    
    
    
     'It can be modified using the Windows Form Designer. 
    
    
    
     'Do not modify it using the code editor.
    
    
    
     <System.Diagnostics.DebuggerStepThrough()> _
    
    
    
     Private Sub InitializeComponent()
    
    
    
     Dim Label6 As System.Windows.Forms.Label
    
    
    
     Dim Label3 As System.Windows.Forms.Label
    
    
    
     Dim Label2 As System.Windows.Forms.Label
    
    
    
     Dim Label1 As System.Windows.Forms.Label
    
    
    
     Me.CityTextBox = New System.Windows.Forms.TextBox()
    
    
    
     Me.AreaRegionTextBox = New System.Windows.Forms.TextBox()
    
    
    
     Me.PostCodeTextBox = New System.Windows.Forms.TextBox()
    
    
    
     Me.AddressTextBox = New System.Windows.Forms.TextBox()
    
    
    
     Me.TableLayoutPanel1 = New System.Windows.Forms.TableLayoutPanel()
    
    
    
     Label6 = New System.Windows.Forms.Label()
    
    
    
     Label3 = New System.Windows.Forms.Label()
    
    
    
     Label2 = New System.Windows.Forms.Label()
    
    
    
     Label1 = New System.Windows.Forms.Label()
    
    
    
     Me.TableLayoutPanel1.SuspendLayout()
    
    
    
     Me.SuspendLayout()
    
    
    
     '
    
    
    
     'Label6
    
    
    
     '
    
    
    
     Label6.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Label6.Location = New System.Drawing.Point(3, 50)
    
    
    
     Label6.Name = "Label6"
    
    
    
     Label6.Size = New System.Drawing.Size(64, 25)
    
    
    
     Label6.TabIndex = 2
    
    
    
     Label6.Text = "City:"
    
    
    
     Label6.TextAlign = System.Drawing.ContentAlignment.MiddleLeft
    
    
    
     '
    
    
    
     'Label3
    
    
    
     '
    
    
    
     Label3.Location = New System.Drawing.Point(356, 25)
    
    
    
     Label3.Name = "Label3"
    
    
    
     Label3.Size = New System.Drawing.Size(51, 23)
    
    
    
     Label3.TabIndex = 2
    
    
    
     Label3.Text = "Region:"
    
    
    
     Label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft
    
    
    
     '
    
    
    
     'Label2
    
    
    
     '
    
    
    
     Label2.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Label2.Location = New System.Drawing.Point(3, 25)
    
    
    
     Label2.Name = "Label2"
    
    
    
     Label2.Size = New System.Drawing.Size(64, 25)
    
    
    
     Label2.TabIndex = 2
    
    
    
     Label2.Text = "PostCode:"
    
    
    
     Label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft
    
    
    
     '
    
    
    
     'Label1
    
    
    
     '
    
    
    
     Me.TableLayoutPanel1.SetColumnSpan(Label1, 2)
    
    
    
     Label1.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Label1.Location = New System.Drawing.Point(3, 0)
    
    
    
     Label1.Name = "Label1"
    
    
    
     Label1.Size = New System.Drawing.Size(347, 25)
    
    
    
     Label1.TabIndex = 0
    
    
    
     Label1.Text = "Address:"
    
    
    
     Label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft
    
    
    
     '
    
    
    
     'CityTextBox
    
    
    
     '
    
    
    
     Me.CityTextBox.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Me.CityTextBox.Location = New System.Drawing.Point(73, 53)
    
    
    
     Me.CityTextBox.Name = "CityTextBox"
    
    
    
     Me.CityTextBox.Size = New System.Drawing.Size(277, 20)
    
    
    
     Me.CityTextBox.TabIndex = 3
    
    
    
     '
    
    
    
     'AreaRegionTextBox
    
    
    
     '
    
    
    
     Me.AreaRegionTextBox.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Me.AreaRegionTextBox.Location = New System.Drawing.Point(413, 28)
    
    
    
     Me.AreaRegionTextBox.Name = "AreaRegionTextBox"
    
    
    
     Me.AreaRegionTextBox.Size = New System.Drawing.Size(277, 20)
    
    
    
     Me.AreaRegionTextBox.TabIndex = 3
    
    
    
     '
    
    
    
     'PostCodeTextBox
    
    
    
     '
    
    
    
     Me.PostCodeTextBox.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Me.PostCodeTextBox.Location = New System.Drawing.Point(73, 28)
    
    
    
     Me.PostCodeTextBox.Name = "PostCodeTextBox"
    
    
    
     Me.PostCodeTextBox.Size = New System.Drawing.Size(277, 20)
    
    
    
     Me.PostCodeTextBox.TabIndex = 3
    
    
    
     '
    
    
    
     'AddressTextBox
    
    
    
     '
    
    
    
     Me.TableLayoutPanel1.SetColumnSpan(Me.AddressTextBox, 2)
    
    
    
     Me.AddressTextBox.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Me.AddressTextBox.Location = New System.Drawing.Point(356, 3)
    
    
    
     Me.AddressTextBox.Name = "AddressTextBox"
    
    
    
     Me.AddressTextBox.Size = New System.Drawing.Size(334, 20)
    
    
    
     Me.AddressTextBox.TabIndex = 1
    
    
    
     '
    
    
    
     'TableLayoutPanel1
    
    
    
     '
    
    
    
     Me.TableLayoutPanel1.ColumnCount = 5
    
    
    
     Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 70.0!))
    
    
    
     Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
    
    
    
     Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 57.0!))
    
    
    
     Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
    
    
    
     Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle())
    
    
    
     Me.TableLayoutPanel1.Controls.Add(Label1, 0, 0)
    
    
    
     Me.TableLayoutPanel1.Controls.Add(Me.AddressTextBox, 2, 0)
    
    
    
     Me.TableLayoutPanel1.Controls.Add(Label2, 0, 1)
    
    
    
     Me.TableLayoutPanel1.Controls.Add(Label3, 2, 1)
    
    
    
     Me.TableLayoutPanel1.Controls.Add(Label6, 0, 2)
    
    
    
     Me.TableLayoutPanel1.Controls.Add(Me.PostCodeTextBox, 1, 1)
    
    
    
     Me.TableLayoutPanel1.Controls.Add(Me.AreaRegionTextBox, 3, 1)
    
    
    
     Me.TableLayoutPanel1.Controls.Add(Me.CityTextBox, 1, 2)
    
    
    
     Me.TableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Me.TableLayoutPanel1.Location = New System.Drawing.Point(0, 0)
    
    
    
     Me.TableLayoutPanel1.Name = "TableLayoutPanel1"
    
    
    
     Me.TableLayoutPanel1.RowCount = 4
    
    
    
     Me.TableLayoutPanel1.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
    
    
    
     Me.TableLayoutPanel1.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
    
    
    
     Me.TableLayoutPanel1.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
    
    
    
     Me.TableLayoutPanel1.RowStyles.Add(New System.Windows.Forms.RowStyle())
    
    
    
     Me.TableLayoutPanel1.Size = New System.Drawing.Size(693, 79)
    
    
    
     Me.TableLayoutPanel1.TabIndex = 1
    
    
    
     '
    
    
    
     'cntAddress
    
    
    
     '
    
    
    
     Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
    
    
    
     Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
    
    
    
     Me.Controls.Add(Me.TableLayoutPanel1)
    
    
    
     Me.Name = "cntAddress"
    
    
    
     Me.Size = New System.Drawing.Size(693, 79)
    
    
    
     Me.TableLayoutPanel1.ResumeLayout(False)
    
    
    
     Me.TableLayoutPanel1.PerformLayout()
    
    
    
     Me.ResumeLayout(False)
    
    
    
    
    
    
    
     End Sub
    
    
    
     Friend WithEvents CityTextBox As System.Windows.Forms.TextBox
    
    
    
     Friend WithEvents AreaRegionTextBox As System.Windows.Forms.TextBox
    
    
    
     Friend WithEvents PostCodeTextBox As System.Windows.Forms.TextBox
    
    
    
     Friend WithEvents AddressTextBox As System.Windows.Forms.TextBox
    
    
    
     Friend WithEvents TableLayoutPanel1 As System.Windows.Forms.TableLayoutPanel
    
    
    
    
    
    
    
    End Class
    
    
    
    
    
    
    
    

    and one of my numerous attempts on the code behind is :

    Public Class cntAddress
    
    
    
     
    
    
    
     <System.ComponentModel.Bindable(True)>
    
    
    
     Public Property Address() As String
    
    
    
     <System.ComponentModel.Bindable(True)>
    
    
    
     Public Property PostCode() As String
    
    
    
     <System.ComponentModel.Bindable(True)>
    
    
    
     Public Property AreaRegion() As String
    
    
    
     <System.ComponentModel.Bindable(True)>
    
    
    
     Public Property City() As String
    
    
    
    
    
    
    
     Private Sub cntAddress_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    
    
    
     Me.AddressTextBox.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me, "Address"))
    
    
    
     Me.PostCodeTextBox.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me, "PostCode"))
    
    
    
     Me.AreaRegionTextBox.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me, "AreaRegion"))
    
    
    
     Me.CityTextBox.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me, "City"))
    
    
    
     End Sub
    
    
    
    
    
    
    
    End Class
    
    
    
    
    
    
    
    

    I now have a main form (frmMain) with the following code behind:

    Partial Class frmMain
    
    
    
     Inherits System.Windows.Forms.Form
    
    
    
    
    
    
    
     'Form overrides dispose to clean up the component list.
    
    
    
     <System.Diagnostics.DebuggerNonUserCode()> _
    
    
    
     Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    
    
    
     Try
    
    
    
      If disposing AndAlso components IsNot Nothing Then
    
    
    
      components.Dispose()
    
    
    
      End If
    
    
    
     Finally
    
    
    
      MyBase.Dispose(disposing)
    
    
    
     End Try
    
    
    
     End Sub
    
    
    
    
    
    
    
     'Required by the Windows Form Designer
    
    
    
     Private components As System.ComponentModel.IContainer
    
    
    
    
    
    
    
     'NOTE: The following procedure is required by the Windows Form Designer
    
    
    
     'It can be modified using the Windows Form Designer. 
    
    
    
     'Do not modify it using the code editor.
    
    
    
     <System.Diagnostics.DebuggerStepThrough()> _
    
    
    
     Private Sub InitializeComponent()
    
    
    
     Me.components = New System.ComponentModel.Container()
    
    
    
     Dim FldFirstNameLabel As System.Windows.Forms.Label
    
    
    
     Dim FldLastNameLabel As System.Windows.Forms.Label
    
    
    
     Me.FldFirstNameTextBox = New System.Windows.Forms.TextBox()
    
    
    
     Me.PersonBindingSource = New System.Windows.Forms.BindingSource(Me.components)
    
    
    
     Me.FldLastNameTextBox = New System.Windows.Forms.TextBox()
    
    
    
     Me.TableLayoutPanel1 = New System.Windows.Forms.TableLayoutPanel()
    
    
    
     Me.CntAddress1 = New BindingCustomControl.cntAddress()
    
    
    
     Me.SplitContainer1 = New System.Windows.Forms.SplitContainer()
    
    
    
     Me.PropertyGrid1 = New System.Windows.Forms.PropertyGrid()
    
    
    
     FldFirstNameLabel = New System.Windows.Forms.Label()
    
    
    
     FldLastNameLabel = New System.Windows.Forms.Label()
    
    
    
     CType(Me.PersonBindingSource, System.ComponentModel.ISupportInitialize).BeginInit()
    
    
    
     Me.TableLayoutPanel1.SuspendLayout()
    
    
    
     CType(Me.SplitContainer1, System.ComponentModel.ISupportInitialize).BeginInit()
    
    
    
     Me.SplitContainer1.Panel1.SuspendLayout()
    
    
    
     Me.SplitContainer1.Panel2.SuspendLayout()
    
    
    
     Me.SplitContainer1.SuspendLayout()
    
    
    
     Me.SuspendLayout()
    
    
    
     '
    
    
    
     'FldFirstNameLabel
    
    
    
     '
    
    
    
     FldFirstNameLabel.AutoSize = True
    
    
    
     FldFirstNameLabel.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     FldFirstNameLabel.Location = New System.Drawing.Point(3, 0)
    
    
    
     FldFirstNameLabel.Name = "FldFirstNameLabel"
    
    
    
     FldFirstNameLabel.Size = New System.Drawing.Size(94, 25)
    
    
    
     FldFirstNameLabel.TabIndex = 2
    
    
    
     FldFirstNameLabel.Text = "First Name:"
    
    
    
     FldFirstNameLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft
    
    
    
     '
    
    
    
     'FldLastNameLabel
    
    
    
     '
    
    
    
     FldLastNameLabel.AutoSize = True
    
    
    
     FldLastNameLabel.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     FldLastNameLabel.Location = New System.Drawing.Point(158, 0)
    
    
    
     FldLastNameLabel.Name = "FldLastNameLabel"
    
    
    
     FldLastNameLabel.Size = New System.Drawing.Size(94, 25)
    
    
    
     FldLastNameLabel.TabIndex = 4
    
    
    
     FldLastNameLabel.Text = "Last Name:"
    
    
    
     FldLastNameLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft
    
    
    
     '
    
    
    
     'FldFirstNameTextBox
    
    
    
     '
    
    
    
     Me.FldFirstNameTextBox.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me.PersonBindingSource, "fldFirstName", True))
    
    
    
     Me.FldFirstNameTextBox.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Me.FldFirstNameTextBox.Location = New System.Drawing.Point(103, 3)
    
    
    
     Me.FldFirstNameTextBox.Name = "FldFirstNameTextBox"
    
    
    
     Me.FldFirstNameTextBox.Size = New System.Drawing.Size(49, 20)
    
    
    
     Me.FldFirstNameTextBox.TabIndex = 3
    
    
    
     '
    
    
    
     'PersonBindingSource
    
    
    
     '
    
    
    
     Me.PersonBindingSource.DataSource = GetType(BindingCustomControl.Person)
    
    
    
     '
    
    
    
     'FldLastNameTextBox
    
    
    
     '
    
    
    
     Me.FldLastNameTextBox.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me.PersonBindingSource, "fldLastName", True))
    
    
    
     Me.FldLastNameTextBox.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Me.FldLastNameTextBox.Location = New System.Drawing.Point(258, 3)
    
    
    
     Me.FldLastNameTextBox.Name = "FldLastNameTextBox"
    
    
    
     Me.FldLastNameTextBox.Size = New System.Drawing.Size(49, 20)
    
    
    
     Me.FldLastNameTextBox.TabIndex = 5
    
    
    
     '
    
    
    
     'TableLayoutPanel1
    
    
    
     '
    
    
    
     Me.TableLayoutPanel1.ColumnCount = 5
    
    
    
     Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 100.0!))
    
    
    
     Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
    
    
    
     Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 100.0!))
    
    
    
     Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
    
    
    
     Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle())
    
    
    
     Me.TableLayoutPanel1.Controls.Add(FldFirstNameLabel, 0, 0)
    
    
    
     Me.TableLayoutPanel1.Controls.Add(Me.FldLastNameTextBox, 3, 0)
    
    
    
     Me.TableLayoutPanel1.Controls.Add(FldLastNameLabel, 2, 0)
    
    
    
     Me.TableLayoutPanel1.Controls.Add(Me.FldFirstNameTextBox, 1, 0)
    
    
    
     Me.TableLayoutPanel1.Controls.Add(Me.CntAddress1, 0, 1)
    
    
    
     Me.TableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Me.TableLayoutPanel1.Location = New System.Drawing.Point(0, 0)
    
    
    
     Me.TableLayoutPanel1.Name = "TableLayoutPanel1"
    
    
    
     Me.TableLayoutPanel1.RowCount = 3
    
    
    
     Me.TableLayoutPanel1.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!))
    
    
    
     Me.TableLayoutPanel1.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
    
    
    
     Me.TableLayoutPanel1.RowStyles.Add(New System.Windows.Forms.RowStyle())
    
    
    
     Me.TableLayoutPanel1.Size = New System.Drawing.Size(311, 262)
    
    
    
     Me.TableLayoutPanel1.TabIndex = 6
    
    
    
     '
    
    
    
     'CntAddress1
    
    
    
     '
    
    
    
     Me.CntAddress1.Address = Nothing
    
    
    
     Me.CntAddress1.AreaRegion = Nothing
    
    
    
     Me.CntAddress1.City = Nothing
    
    
    
     Me.TableLayoutPanel1.SetColumnSpan(Me.CntAddress1, 4)
    
    
    
     <strong>Me.CntAddress1.DataBindings.Add(New System.Windows.Forms.Binding("Address", Me.PersonBindingSource, "fldAddress", True))
    
    
    
     Me.CntAddress1.DataBindings.Add(New System.Windows.Forms.Binding("AreaRegion", Me.PersonBindingSource, "fldRegion", True))
    
    
    
     Me.CntAddress1.DataBindings.Add(New System.Windows.Forms.Binding("City", Me.PersonBindingSource, "fldCity", True))
    
    
    
     Me.CntAddress1.DataBindings.Add(New System.Windows.Forms.Binding("PostCode", Me.PersonBindingSource, "fldPostCode", True))</strong>
    
    
    
     Me.CntAddress1.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Me.CntAddress1.Location = New System.Drawing.Point(3, 28)
    
    
    
     Me.CntAddress1.Name = "CntAddress1"
    
    
    
     Me.CntAddress1.PostCode = Nothing
    
    
    
     Me.CntAddress1.Size = New System.Drawing.Size(304, 231)
    
    
    
     Me.CntAddress1.TabIndex = 6
    
    
    
     '
    
    
    
     'SplitContainer1
    
    
    
     '
    
    
    
     Me.SplitContainer1.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Me.SplitContainer1.Location = New System.Drawing.Point(0, 0)
    
    
    
     Me.SplitContainer1.Name = "SplitContainer1"
    
    
    
     '
    
    
    
     'SplitContainer1.Panel1
    
    
    
     '
    
    
    
     Me.SplitContainer1.Panel1.Controls.Add(Me.TableLayoutPanel1)
    
    
    
     '
    
    
    
     'SplitContainer1.Panel2
    
    
    
     '
    
    
    
     Me.SplitContainer1.Panel2.Controls.Add(Me.PropertyGrid1)
    
    
    
     Me.SplitContainer1.Size = New System.Drawing.Size(433, 262)
    
    
    
     Me.SplitContainer1.SplitterDistance = 311
    
    
    
     Me.SplitContainer1.TabIndex = 7
    
    
    
     '
    
    
    
     'PropertyGrid1
    
    
    
     '
    
    
    
     Me.PropertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill
    
    
    
     Me.PropertyGrid1.Location = New System.Drawing.Point(0, 0)
    
    
    
     Me.PropertyGrid1.Name = "PropertyGrid1"
    
    
    
     Me.PropertyGrid1.Size = New System.Drawing.Size(118, 262)
    
    
    
     Me.PropertyGrid1.TabIndex = 0
    
    
    
     '
    
    
    
     'frmMain
    
    
    
     '
    
    
    
     Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
    
    
    
     Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
    
    
    
     Me.ClientSize = New System.Drawing.Size(433, 262)
    
    
    
     Me.Controls.Add(Me.SplitContainer1)
    
    
    
     Me.Name = "frmMain"
    
    
    
     Me.Text = "Main Form"
    
    
    
     CType(Me.PersonBindingSource, System.ComponentModel.ISupportInitialize).EndInit()
    
    
    
     Me.TableLayoutPanel1.ResumeLayout(False)
    
    
    
     Me.TableLayoutPanel1.PerformLayout()
    
    
    
     Me.SplitContainer1.Panel1.ResumeLayout(False)
    
    
    
     Me.SplitContainer1.Panel2.ResumeLayout(False)
    
    
    
     CType(Me.SplitContainer1, System.ComponentModel.ISupportInitialize).EndInit()
    
    
    
     Me.SplitContainer1.ResumeLayout(False)
    
    
    
     Me.ResumeLayout(False)
    
    
    
    
    
    
    
     End Sub
    
    
    
     Friend WithEvents PersonBindingSource As System.Windows.Forms.BindingSource
    
    
    
     Friend WithEvents FldFirstNameTextBox As System.Windows.Forms.TextBox
    
    
    
     Friend WithEvents FldLastNameTextBox As System.Windows.Forms.TextBox
    
    
    
     Friend WithEvents TableLayoutPanel1 As System.Windows.Forms.TableLayoutPanel
    
    
    
     Friend WithEvents CntAddress1 As BindingCustomControl.cntAddress
    
    
    
     Friend WithEvents SplitContainer1 As System.Windows.Forms.SplitContainer
    
    
    
     Friend WithEvents PropertyGrid1 As System.Windows.Forms.PropertyGrid
    
    
    
    
    
    
    
    End Class
    
    
    
    
    
    
    
    

    and the following code behind:

    Public Class frmMain
    
    
    
    
    
    
    
    
    
    
    
     Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
    
    
     Me.PersonBindingSource.DataSource = New Person With {.fldFirstName = "test", .fldLastName = "tester"}
    
    
    
     Me.PropertyGrid1.SelectedObject = Me.PersonBindingSource.DataSource
    
    
    
     End Sub
    
    
    
    
    
    
    
    End Class
    
    
    
    

    The problem with this thing is that the custom control updates only the last edited field and the binding source resets all the rest of the fields to their initial values. Thus, in order to edit all fields you must edit a fields, loose focus on the custom control and then edit the next field etc... I have even tried to create the corresponding PropertyNameChanged (AddressChanged, PostCodeChanged etc) events which I threw on lostfocus of each editing control but without any luck...

    I have found two posts that look similar to my problem:

    From both of them I get the feeling that databinding is not supported on custom entities even though they do implement the INotifyPropertyChanged interface... Is this the case? Should I stop trying to make reusable controls?

    Thanks in advance,

    Andreas

    PS: Source code of the solution is available at http://cid-2ddad65200a5fb58.office.live.com/self.aspx/Public%20Folder/BindingCustomControl.zip

    • Edited by Andreas Botsikas Monday, July 26, 2010 7:25 PM added source code link
    Monday, July 26, 2010 7:20 PM

Answers

  • Finally I did it :) Thank you very much Kira for your guidance. The final solution is available at http://cid-2ddad65200a5fb58.office.live.com/self.aspx/Public%20Folder/BindingCustomControl.Final.zip 

    I have created a self binding datasource in the control (as you suggested) and then in the main form I changed the datasource update mode to onpropertychanged and everything worked just fine.

    The problem was on the updating mechanism which updated the properties of the person class on lost focus. The control's binding source was changing one property from the person class which was then firing the property changed event of the person class causing an update on the rest of the textboxes and thus no other update was propagated from the control to the person class...

    I have also noticed the wierd property grid behavior but I didn't bother... who knows if this is a bug or not...

    Thanks again for your help on figuring this out.

    Best regards,

    Andreas

    Wednesday, July 28, 2010 11:48 AM

All replies

  • Hi Andreas,

     

    I have download and test your code. The issue can be reproduced on my side. Here is my understanding of your code.

     

    Me.PersonBindingSource.DataSource = New Person With {.fldFirstName = "test", .fldLastName = "tester"}

    Me.PropertyGrid1.SelectedObject = Me.PersonBindingSource.DataSource

    You have bound the PropertyGrid1 with Person instance. Then in the cntAddress user control, you have bound each textbox to the related property of cntAddress class. In the frmMain, you have bound cntAddress’s 4 properties with Person instance related properties. When you make any change in cntAddress user control’s textbox the property value of cntAddress changes. But the cntAddress class doesn’t implement INotifyPropertyChanged interface. How change those changes notify the Person object?

     

    I suggest you to simply the design. Directly bind the User Control’s 4 textbox with Person’s 4 properties. Otherwise you have to implement INotifyPropertyChanged for cntAddress class.

     

    Sincerely,

    Kira Qian

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework!
    Tuesday, July 27, 2010 3:16 AM
  • Hello Kira,

    Thank you for your suggestion. As a matter of fact, I have tried to implement the INotifyPropertyChanged in one of my early attempts. Unfortunately this doesn't work either. I have uploaded a new version of my test project on http://cid-2ddad65200a5fb58.office.live.com/self.aspx/Public%20Folder/BindingCustomControl.v2.zip

    cntAddressINotify implements the INotifyPropertyChanged event and I threw it everywhere I could without being able to notify the person class...

    frmMain_PropertyBindings is the form that hosts the cntAddressINotify controls and doesn't work well...

    cntAddress_DirectTextboxBinding exposes the textboxes (declaring them public).

    frmMain_DirectTextBoxBinding works just fine sinse I bind the text properties of the exposed textboxes (on the load event, even though I could also do it from the property window) to the actual data.

    The problem with the working implementation is that I would like to add some validation logic before returning the actual text value from the textboxes.

    Can you please help me out on how I should design the control in order to make it expose working bindable properties?

    Thanks in advance!

    Andreas

    Tuesday, July 27, 2010 9:00 AM
  • Thank you for sharing your project again. The direct control binding works fine on my side. But the previous binding after you implement the interface still have the issue. Then I tried to simplify your project into the following one. This project also works fine. You can download my test sample here.

    http://cid-ee362b84156dcc82.office.live.com/self.aspx/MSDN/Solution/%5E52010.7.28%5E6MultiCtrlBd.zip

     

    And also I found the propertygrid in your sample doesn’t refresh 3 properties value until you click on each of them. I don’t know why. This doesn’t happen in my sample.

     

    Sincerely,

    Kira Qian

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework!
    Wednesday, July 28, 2010 4:27 AM
  • Finally I did it :) Thank you very much Kira for your guidance. The final solution is available at http://cid-2ddad65200a5fb58.office.live.com/self.aspx/Public%20Folder/BindingCustomControl.Final.zip 

    I have created a self binding datasource in the control (as you suggested) and then in the main form I changed the datasource update mode to onpropertychanged and everything worked just fine.

    The problem was on the updating mechanism which updated the properties of the person class on lost focus. The control's binding source was changing one property from the person class which was then firing the property changed event of the person class causing an update on the rest of the textboxes and thus no other update was propagated from the control to the person class...

    I have also noticed the wierd property grid behavior but I didn't bother... who knows if this is a bug or not...

    Thanks again for your help on figuring this out.

    Best regards,

    Andreas

    Wednesday, July 28, 2010 11:48 AM