BUG: Text Box Controls Data Bound on Tab Controls

A

Andrew McKendrick

Hi,

I've noticed a bug in VB.NET (latest .NET Framework)...

- I have a TabControl on a form with several tabs.
- Each tab contains text boxes that are bound to fields in a data source
(DataBindings).
- When I display a record and then try to access the .Text property of one
of the text boxes on any tab except the current tab, the result is an Empty
string.

This occurs even though the fields that the text boxes are bound to have
data in them. If I display the tab and then try to read the contents of the
Text Boxes, then the data is there.

Anyone know if there is a work around to this? Some way to force the text
boxes to grab the data before they are displayed?

Thanks in advance,

Andrew
 
C

Cor Ligthert

Hi Andrew,

I tried to simulate your bug, can you tell me what is different in your
situation because with this everything goes even better than I expected?

Cor

\\\a form with a tabcontrol with 2 tabpages with on each a textbox
Dim bool As Boolean
Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Dim dt As New DataTable
dt.Columns.Add("my")
Dim dr As DataRow = dt.NewRow
dr(0) = "Hello"
dt.Rows.Add(dr)
Me.TextBox1.DataBindings.Add("text", dt, "my")
Me.TextBox2.DataBindings.Add("text", dt, "my")
bool = True
End Sub
Private Sub TabControl1_SelectedIndexChanged(ByVal _
sender As Object, ByVal e As System.EventArgs) Handles _
TabControl1.SelectedIndexChanged
If bool Then
Select Case TabControl1.SelectedIndex
Case 0
MessageBox.Show("I am textbox2 and the value = " &
TextBox2.Text)
Case 1
MessageBox.Show("I am textbox1 and the value = " &
TextBox1.Text)
End Select
End If
End Sub
///

,
 
A

Andrew McKendrick

Hi Cor,

I tried your code, and yes it does work. But I'm using a DataSet that is
bound to an ODBC data source. Try the code that I have below, and you'll see
what I mean.

--- BEGINNING OF CODE SEGMENT ---
Public Class Form1

Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

Public Sub New()

MyBase.New()

'This call is required by the Windows Form Designer.

InitializeComponent()

'Add any initialization after the InitializeComponent() call

End Sub

'Form 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

'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.

Friend WithEvents TabControl1 As System.Windows.Forms.TabControl

Friend WithEvents TabPage1 As System.Windows.Forms.TabPage

Friend WithEvents TabPage2 As System.Windows.Forms.TabPage

Friend WithEvents TextBox1 As System.Windows.Forms.TextBox

Friend WithEvents TextBox2 As System.Windows.Forms.TextBox

Friend WithEvents DataSet1 As System.Data.DataSet

Friend WithEvents DataTable1 As System.Data.DataTable

Friend WithEvents DataColumn1 As System.Data.DataColumn

Friend WithEvents DataColumn2 As System.Data.DataColumn

<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

Me.TabControl1 = New System.Windows.Forms.TabControl

Me.TabPage1 = New System.Windows.Forms.TabPage

Me.TextBox1 = New System.Windows.Forms.TextBox

Me.TabPage2 = New System.Windows.Forms.TabPage

Me.TextBox2 = New System.Windows.Forms.TextBox

Me.DataSet1 = New System.Data.DataSet

Me.DataTable1 = New System.Data.DataTable

Me.DataColumn1 = New System.Data.DataColumn

Me.DataColumn2 = New System.Data.DataColumn

Me.TabControl1.SuspendLayout()

Me.TabPage1.SuspendLayout()

Me.TabPage2.SuspendLayout()

CType(Me.DataSet1, System.ComponentModel.ISupportInitialize).BeginInit()

CType(Me.DataTable1, System.ComponentModel.ISupportInitialize).BeginInit()

Me.SuspendLayout()

'

'TabControl1

'

Me.TabControl1.Controls.Add(Me.TabPage1)

Me.TabControl1.Controls.Add(Me.TabPage2)

Me.TabControl1.Location = New System.Drawing.Point(24, 40)

Me.TabControl1.Name = "TabControl1"

Me.TabControl1.SelectedIndex = 0

Me.TabControl1.Size = New System.Drawing.Size(248, 208)

Me.TabControl1.TabIndex = 0

'

'TabPage1

'

Me.TabPage1.Controls.Add(Me.TextBox1)

Me.TabPage1.Location = New System.Drawing.Point(4, 22)

Me.TabPage1.Name = "TabPage1"

Me.TabPage1.Size = New System.Drawing.Size(240, 182)

Me.TabPage1.TabIndex = 0

Me.TabPage1.Text = "TabPage1"

'

'TextBox1

'

Me.TextBox1.DataBindings.Add(New System.Windows.Forms.Binding("Text",
Me.DataSet1, "Table1.Column1"))

Me.TextBox1.Location = New System.Drawing.Point(80, 56)

Me.TextBox1.Name = "TextBox1"

Me.TextBox1.TabIndex = 0

Me.TextBox1.Text = "TextBox1"

'

'TabPage2

'

Me.TabPage2.Controls.Add(Me.TextBox2)

Me.TabPage2.Location = New System.Drawing.Point(4, 22)

Me.TabPage2.Name = "TabPage2"

Me.TabPage2.Size = New System.Drawing.Size(240, 182)

Me.TabPage2.TabIndex = 1

Me.TabPage2.Text = "TabPage2"

'

'TextBox2

'

Me.TextBox2.DataBindings.Add(New System.Windows.Forms.Binding("Text",
Me.DataSet1, "Table1.Column2"))

Me.TextBox2.Location = New System.Drawing.Point(120, 80)

Me.TextBox2.Name = "TextBox2"

Me.TextBox2.TabIndex = 0

Me.TextBox2.Text = "TextBox2"

'

'DataSet1

'

Me.DataSet1.DataSetName = "NewDataSet"

Me.DataSet1.Locale = New System.Globalization.CultureInfo("en-US")

Me.DataSet1.Tables.AddRange(New System.Data.DataTable() {Me.DataTable1})

'

'DataTable1

'

Me.DataTable1.Columns.AddRange(New System.Data.DataColumn() {Me.DataColumn1,
Me.DataColumn2})

Me.DataTable1.TableName = "Table1"

'

'DataColumn1

'

Me.DataColumn1.ColumnName = "Column1"

'

'DataColumn2

'

Me.DataColumn2.ColumnName = "Column2"

'

'Form1

'

Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)

Me.ClientSize = New System.Drawing.Size(292, 273)

Me.Controls.Add(Me.TabControl1)

Me.Name = "Form1"

Me.Text = "Form1"

Me.TabControl1.ResumeLayout(False)

Me.TabPage1.ResumeLayout(False)

Me.TabPage2.ResumeLayout(False)

CType(Me.DataSet1, System.ComponentModel.ISupportInitialize).EndInit()

CType(Me.DataTable1, System.ComponentModel.ISupportInitialize).EndInit()

Me.ResumeLayout(False)

End Sub

#End Region

Dim bool As Boolean

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

dim a as DataRow

DIm b(1) as String

b(0) = "dummy1"

b(1) = "dummy2"


a = dataset1.Tables(0).Rows.Add(b)


msgbox(textbox2.Text)

End Sub

End Class

---- END OF CODE SEGMENT ----

Thanks,

Andrew
 
A

Andrew McKendrick

Hi Cor,

I made a mistake, in my reply post (on the newsgroup). I thought that your
code worked, but it never. The only reason it worked is because I clicked
the second tab and then the first tab (by displaying the second tab the
value in that field was loaded).

But try adding the following code segment to the Form_Click event and when
you run your code DO NOT click the second tab, but click the form instead
and you'll see the message box displays either an empty string or "textbox2"
depending on what the text value of the text box was at design time and NOT
"Hello" as it should.
MessageBox.Show("I am textbox2 and the value = " & TextBox2.Text)

Let me know if you experience something different, because if you do, either
you are misunderstanding me, or something is wrong with my copy of .NET :)

Thanks,

Andrew
 
C

Cor Ligthert

Hi Andrew,

You wrote this
When I display a record and then try to access the .Text property of one
of the text boxes on any tab except the current tab, the result is an Empty
string.

However in the situation you showed me they are not displayed yet.

Change this in your code than you see the difference when they are
displayed.
(and when you next time paste in code paste and copy it first using a
notebook, now it is horrable to read)
\\\\
Dim a As DataRow
Dim b(1) As String
b(0) = "dummy1"
b(1) = "dummy2"
a = DataSet1.Tables(0).Rows.Add(b)
Me.TabPage2.Show()
Me.TabPage1.Show()
MsgBox(TextBox2.Text)
///
I hope this helps?

Cor
 
C

Cor Ligthert

Andrew,

However it is better to use the values from the table, here a sample, I used
this time my sample because of the reading trouble with yours, you can
change the dt to the dataset or just write before it
dim dt as datatable = ds.tables(0)

\\\
Dim a As DataRow
Dim b(1) As String
b(0) = "dummy1"
b(1) = "dummy2"
a = dt.Rows.Add(b)
BindingContext(dt).Position = dt.Rows.Count
MsgBox(TextBox1.Text)
Dim c As String = dt.Rows(BindingContext(dt).Position)(0).ToString
MessageBox.Show(c)
///
 
A

Andrew McKendrick

Hi Cor,

These two lines:
Me.TabPage2.Show()
Me.TabPage1.Show()

seem to fix the problem.

But I must admit that you wouldn't think work arounds like this should be
necessary.

I'll try it in my application, but it seems like it's going to work.

Thanks for your perspective and help,

Andrew
 
M

Michael Maes

Hi Andrew,

That is a problem with the BindingContext. It seems that Binding is initialized when a control is shown. If the control is not yet shown, BindingContext does not know that there is a control that needs to be monitored for value change. In that case, to set or get the values to/from the control, set/get the values to/from a DataRowView directly.

HTH,

Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top