Sync databound combobox to current bound record in form

D

dbuchanan

VS2005
I've been reading all the help I can on the topic (MSDN, other) but I
can't make sense of this.

Desired behavior;
The user is to choose from the displayed list of the databound combobox
and the coresponding 'Id' from the lookup table is to be inserted into
the field of the new record.

I have two simple tables. "tblPerson" is the data table. The lookup
table is "lkpPersonType".
The combobox dropdownstyle is "dropdownlist" to limit the user to the
list.

Here are the two tables
"tblPerson"
Id int IDENTITY (1, 1) NOT NULL ,
Name varchar(50),
Address varchar(50),
fkPersonTypeId smallint

"lkpPersonType"
pkPersonTypeId smallint IDENTITY (1, 1) NOT NULL ,
Type varchar(50) NOT NULL ,

The form has two binding sources "TblPersonBindingSource" for the data
table and "lkpPersonTypeBindingSource" for the lookup table.

The Display Member of the combobox is the "Type" field and the value
member is "pkPersonTypeId" field.

The Text property of the combobox is set to the "fkPersonTypeId" of the
table "tblPerson".

The next parts I am unsure of...

I did not set the Selected Value (???)
I set the Selected Item to the "Type" field of the lookup table
lkpPersonType

When I run the app the combobox populates. The data seems to display
properly for the first record, but the combobox does not cycle through
the values I know are assigned to it for the other records. In other
words it is not properly bound. However there is a relationship between
the two tables in the dataset, but the relationship is not specifically
refered to in the form.

Here is my code in the load event;
\\
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Me.TblPersonTableAdapter.Fill(Me.DataSet1.tblPerson)
Me.LkpPersonTypeTableAdapter.Fill(Me.DataSet1.lkpPersonType)

Me.FkPersonTypeIdComboBox.DataSource =
Me.lkpPersonTypeBindingSource
Me.FkPersonTypeIdComboBox.DisplayMember = "Type"
Me.FkPersonTypeIdComboBox.ValueMember = "pkPersonTypeId"
'Me.FkPersonTypeIdComboBox.SelectedValue = ???

'Me.FkPersonTypeIdComboBox.SelectedItem = "Type"

Me.FkPersonTypeIdComboBox.Text =
"TblPersonBindingSource.fkPersonTypeId"

End Sub
//

Please help me make some sense of this and get it working.

Thank you,
dbuchanan
 
B

Bart Mermuys

Hi,

dbuchanan said:
VS2005
I've been reading all the help I can on the topic (MSDN, other) but I
can't make sense of this.

Desired behavior;
The user is to choose from the displayed list of the databound combobox
and the coresponding 'Id' from the lookup table is to be inserted into
the field of the new record.

I have two simple tables. "tblPerson" is the data table. The lookup
table is "lkpPersonType".
The combobox dropdownstyle is "dropdownlist" to limit the user to the
list.

Here are the two tables
"tblPerson"
Id int IDENTITY (1, 1) NOT NULL ,
Name varchar(50),
Address varchar(50),
fkPersonTypeId smallint

"lkpPersonType"
pkPersonTypeId smallint IDENTITY (1, 1) NOT NULL ,
Type varchar(50) NOT NULL ,

The form has two binding sources "TblPersonBindingSource" for the data
table and "lkpPersonTypeBindingSource" for the lookup table.

The Display Member of the combobox is the "Type" field and the value
member is "pkPersonTypeId" field.

The Text property of the combobox is set to the "fkPersonTypeId" of the
table "tblPerson".

No need to set or bind Text property. You need to bind SelectedValue to the
fk of the master BindingSource.
See code below.
The next parts I am unsure of...

I did not set the Selected Value (???)
I set the Selected Item to the "Type" field of the lookup table
lkpPersonType

When I run the app the combobox populates. The data seems to display
properly for the first record, but the combobox does not cycle through
the values I know are assigned to it for the other records. In other
words it is not properly bound. However there is a relationship between
the two tables in the dataset, but the relationship is not specifically
refered to in the form.

Here is my code in the load event;
\\

Me.TblPersonTableAdapter.Fill(Me.DataSet1.tblPerson)
Me.LkpPersonTypeTableAdapter.Fill(Me.DataSet1.lkpPersonType)

' bind lookup
Me.FkPersonTypeIdComboBox.DataSource =
Me.lkpPersonTypeBindingSource
Me.FkPersonTypeIdComboBox.DisplayMember = "Type"
Me.FkPersonTypeIdComboBox.ValueMember = "pkPersonTypeId"

' bind lookup to master
Me.FkPersonTypeIdComboBox.DataBindings.Add( _
"SelectedValue", TblPersonBindingSource, "fkPersonTypeId")

No need to bind or set Text.

HTH,
Greetings
 
D

dbuchanan

Hi Bart,

1.)
It works! Yet there is a mystery in this to me...

This control was automatically bound in "Form1.Designer.vb" when I
draged the field from DataSources window onto the form. Here is the
binding statement it produced;
\\
Me.FkPersonTypeIdComboBox.DataBindings.Add( _
New System.Windows.Forms.Binding("Text", _
Me.TblPersonBindingSource, "fkPersonTypeId", True))
//

So why do I need two binding statements by adding this line that you
gave me?;
\\
Me.FkPersonTypeIdComboBox.DataBindings.Add( _
"SelectedValue", TblPersonBindingSource, "fkPersonTypeId")
//
Can you explain?

2.)
(You helped me with "Public Class NComboBox" for VS2003 last Sept. -
Oct. Nice to hear from you again.)

Back then you said that VS2005 handles null for ComboBoxes. Could you
help me one step further?

I want the ComboBox to appear empty before the user makes a selection
for a new row and the underlying field to remain null if the user saves
the record without making a selection. Is this what you meant when you
said that vs2005 comboBoxes support Null values?

If I can do this please tell me how I would go about it.

Thank you,
dbuchanan
 
B

Bart Mermuys

Hi,

dbuchanan said:
Hi Bart,

1.)
It works! Yet there is a mystery in this to me...

This control was automatically bound in "Form1.Designer.vb" when I
draged the field from DataSources window onto the form. Here is the
binding statement it produced;
\\
Me.FkPersonTypeIdComboBox.DataBindings.Add( _
New System.Windows.Forms.Binding("Text", _
Me.TblPersonBindingSource, "fkPersonTypeId", True))
//

So why do I need two binding statements by adding this line that you
gave me?;
\\
Me.FkPersonTypeIdComboBox.DataBindings.Add( _
"SelectedValue", TblPersonBindingSource, "fkPersonTypeId")
//
Can you explain?

In some situations you need to bind Text, but in your situtation (fk-pk) you
need to bind SelectedValue and _not_ Text. I know the designer binds Text
when you drag it from Data Sources, but you must clear the Text binding and
bind only SelectedValue.
2.)
(You helped me with "Public Class NComboBox" for VS2003 last Sept. -
Oct. Nice to hear from you again.)

Back then you said that VS2005 handles null for ComboBoxes. Could you
help me one step further?

Well, big disappointment, there are still some problems left with null
values though some are fixed.
I want the ComboBox to appear empty before the user makes a selection
for a new row and the underlying field to remain null if the user saves
the record without making a selection.

That should work, just set ComboBox.FormattingEnabled to true, that should
do it.

HTH,
Greetings
 
D

dbuchanan

Bart,

I've followed these guidelines in my working application. However there
is an interesting yet serious glitch.

There is a slightly different glitch depending on how the combobox is
configured. The glitches are very specific so I will careful explain
them in separate sections below.

I'll name and describe these like this:
Glitch 1 - Occurs when the comboBox is configured using properties
window and the "ComboBox Tasks" box.
Glitch 2 - Occurs when the comboBox is configured using code only
(except that the control was dragged from the DataSouces window)
See the sections below...

In both cases the forms that hold the comboboxes are contained in
auxiliary forms ('A' and 'B').

The form-use scenario goes like this:
The user configures data for records in the DataGridView by opening one
and then another of these four forms.
I believe the glitches are related even though they appear at different
times in this scenario.

Glitch 1 (properties & generated code) False data is displayed when the
form opens for the first time and displays correctly for all subsequent
times the form is opened.

Glitch 2 (Manual code) The for opens and seems to operate correctly
when it first opens, but always throws an error the second time it is
opened (whether data is changed or not).

Now for greater description and code.
=====================================================
Glitch 1 - Occurs when the comboBox is configured using properties
window and the "ComboBox Tasks" box.
-----------------------------------------------------
Behavior:

· This behavior happens on a session basis, not on a record basis.

· The first time form 'A' is opened you cannot trust what you see in
the comboBox. The comboBox will *always* display data.
· However every subsequent time form 'A' is opened in the same
session (no mater if it is the same record or a completely different
record, you can *always* trust what the comboBox displays.

Form 'B' same as form 'A'
· When the user opens form 'B' for the first time you cannot trust
what you see in the comboBox. The comboBox will *always* display data.
· And every subsequent time form 'B' is opened in the same session
you can *always* trust what the comboBox displays.

Summary of Glitch 1:
· The first time a form is opened in a session the combox will
*always* be Untrustworthy.
· The second time (and thereafter) a form is opened in a session the
combobox will *always* be Trustworthy.

Here is the code that opens the form (same for glitch 1 and 2):
\\\
Protected Sub btnMachineInfo_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles btnMachineInfo.Click

' Indicate the mode used to open this form so the certain
buttons can be disabled and others enabled
bFormOpenedDirectly = True

' Populate the values to be used in the opening form as
parameters in tableAdapter FillBy statement
GetQuoteIdVersionId()

Dim f As Form = MachineInformation
Me.Visible = False
' Open as dialog so that the bFormOpenedDirecly can be
cleared after returning
f.ShowDialog()
Me.Visible = True

bFormOpenedDirectly = False

End Sub
///

Here is the code in the opening forms load method in Glitch 1 scenario:
\\\
Private Sub MachineVersion_Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles MyBase.Load

' Change Text of inherited label
Me.lblFormTitle.Text = "Machine Information"

' Enable buttons based on how the form is opened
Me.btnNext.Enabled = Not QuotesOverview.bFormOpenedDirectly
Me.btnPrevious.Enabled = Not QuotesOverview.bFormOpenedDirectly
Me.btnSave.Enabled = QuotesOverview.bFormOpenedDirectly
'Me.btnCancel.Visible = False

' Fill TableAdapters
Me.Tbl010QuoteTableAdapter.FillByQuoteId(DataSet1.tbl010Quote,
QuotesOverview.quoteId)

Me.Tbl020VersionTableAdapter.FillByQuoteAndVersion(DataSet1.tbl020Version,
QuotesOverview.quoteId, QuotesOverview.versionId)
Me.Tbl050OptionTableAdapter.Fill(Me.DataSet1.tbl050Option)

' Get and display the Quote Number formatted the way users
expect to see it
CurrentQuoteIdLabel.Text = QuotesOverview.GetIAQuoteNumber

End Sub
///

Here is pertinent comboBox code from Designer generated code within
MachineIformation.Desiger.vb:
\\\
'Op1QuantityofNestsComboBox
'
Me.Op1QuantityofNestsComboBox.DataBindings.Add(New
System.Windows.Forms.Binding("SelectedValue",
Me.Tbl020VersionBindingSource, "op1QuantityofNests", True))
Me.Op1QuantityofNestsComboBox.DataSource =
Me.QuanNestsBindingSource
Me.Op1QuantityofNestsComboBox.DisplayMember = "OptionText"
Me.Op1QuantityofNestsComboBox.DropDownStyle =
System.Windows.Forms.ComboBoxStyle.DropDownList
Me.Op1QuantityofNestsComboBox.FormattingEnabled = True
Me.Op1QuantityofNestsComboBox.Location = New
System.Drawing.Point(114, 344)
Me.Op1QuantityofNestsComboBox.Name =
"Op1QuantityofNestsComboBox"
Me.Op1QuantityofNestsComboBox.Size = New
System.Drawing.Size(121, 21)
Me.Op1QuantityofNestsComboBox.TabIndex = 34
Me.Op1QuantityofNestsComboBox.ValueMember = "pkOptionId"
///


=== End of the Glitch 1 description =====================



=====================================================
Glitch 2 - Occurs when the comboBox is configured using code only
(except that the control was dragged from the DataSouces window)
-----------------------------------------------------
Behavior:

· This behavior cannot be associated with session or record because
it results in an error.

· The first time form 'A' is opened the comboBox displays properly
and as expected. The comboBox is empty if the field is empty. The
comboBox show the appropriate values if the values have been saved to
that field.
· However when you try to open form 'A' the second time an error is
thrown.

Form 'B' has the same behavior as form 'A'

The code to open the form is the same for both glitch scenarios:

Here is the code in the opening form load method in Glitch 2 scenario:
\\\
Private Sub MachineVersion_Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles MyBase.Load

' Change Text of inherited label
Me.lblFormTitle.Text = "Machine Information"

' Enable buttons based on how the form is opened
Me.btnNext.Enabled = Not QuotesOverview.bFormOpenedDirectly
Me.btnPrevious.Enabled = Not QuotesOverview.bFormOpenedDirectly
Me.btnSave.Enabled = QuotesOverview.bFormOpenedDirectly
'Me.btnCancel.Visible = False

' Fill TableAdapters
Me.Tbl010QuoteTableAdapter.FillByQuoteId(DataSet1.tbl010Quote,
QuotesOverview.quoteId)

Me.Tbl020VersionTableAdapter.FillByQuoteAndVersion(DataSet1.tbl020Version,
QuotesOverview.quoteId, QuotesOverview.versionId)
Me.Tbl050OptionTableAdapter.Fill(Me.DataSet1.tbl050Option)

' Get and display the Quote Number formatted the way users
expect to see it
CurrentQuoteIdLabel.Text = QuotesOverview.GetIAQuoteNumber

'The following code is unique to Glitch 2 because it is manually
written.
' PartSize Combobox
Me.Op1PartSizeComboBox.DataSource = Me.PartSizeBindingSource
Me.Op1PartSizeComboBox.DisplayMember = "OptionText"
Me.Op1PartSizeComboBox.ValueMember = "pkOptionId"
Me.Op1PartSizeComboBox.FormattingEnabled = True

' bind lookup to master
' <<< The line below throws the error when the form is opened the
second time. >>>
Me.Op1PartSizeComboBox.DataBindings.Add("SelectedValue",
Me.Tbl020VersionBindingSource, "op1PartSize")

End Sub
///

Here is pertinent comboBox code from Designer generated code within
MachineIformation.Desiger.vb:
\\\
'Op1PartSizeComboBox
'
Me.Op1PartSizeComboBox.DropDownStyle =
System.Windows.Forms.ComboBoxStyle.DropDownList
Me.Op1PartSizeComboBox.FormattingEnabled = True
Me.Op1PartSizeComboBox.Location = New System.Drawing.Point(114,
317)
Me.Op1PartSizeComboBox.Name = "Op1PartSizeComboBox"
Me.Op1PartSizeComboBox.Size = New System.Drawing.Size(121, 21)
Me.Op1PartSizeComboBox.TabIndex = 33
///

Here is the error message
\\\
System.ArgumentException was unhandled
Message="This causes two bindings in the collection to bind to the
same property.
Parameter name: binding"
ParamName="binding"
Source="System.Windows.Forms"
StackTrace:
at
System.Windows.Forms.ControlBindingsCollection.CheckDuplicates(Binding
binding)
at System.Windows.Forms.Binding.CheckBinding()
at
System.Windows.Forms.Binding.SetBindableComponent(IBindableComponent
value)
at
System.Windows.Forms.ControlBindingsCollection.AddCore(Binding
dataBinding)
at System.Windows.Forms.ControlBindingsCollection.Add(String
propertyName, Object dataSource, String dataMember, Boolean
formattingEnabled, DataSourceUpdateMode updateMode, Object nullValue,
String formatString, IFormatProvider formatInfo)
at System.Windows.Forms.ControlBindingsCollection.Add(String
propertyName, Object dataSource, String dataMember)
at
QmsUserInterface.MachineInformation.MachineVersion_Load(Object sender,
EventArgs e) in D:\DBuchanan MyDocuments\IA\Dev Projects\QMS I\AppDev -
QMS\QMS_01 2006-01-30\QmsUI\Forms_Derived01\MachineInformation.vb:line
43
at System.EventHandler.Invoke(Object sender, EventArgs e)
at System.Windows.Forms.Form.OnLoad(EventArgs e)
at System.Windows.Forms.Form.SetVisibleCore(Boolean value)
at System.Windows.Forms.Control.set_Visible(Boolean value)
at
System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32
reason, ApplicationContext context)
at
System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32
reason, ApplicationContext context)
at System.Windows.Forms.Form.ShowDialog(IWin32Window owner)
at System.Windows.Forms.Form.ShowDialog()
at QmsUserInterface.QuotesOverview.btnMachineInfo_Click(Object
sender, EventArgs e) in D:\DBuchanan MyDocuments\IA\Dev Projects\QMS
I\AppDev - QMS\QMS_01
2006-01-30\QmsUI\Forms_Derived01\QuotesOverview.vb:line 210
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m,
MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at
System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at
System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr
hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at
System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at
System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)
at
System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32
reason, ApplicationContext context)
at
System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32
reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(ApplicationContext
context)
at
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
at
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
at
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[]
commandLine)
at QmsUserInterface.My.MyApplication.Main(String[] Args) in
17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[]
args)
at System.AppDomain.ExecuteAssembly(String assemblyFile,
Evidence assemblySecurity, String[] args)
at
Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object
state)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
///

=== End of the Glitch 2 description =====================


What could be causing these behaviors?
What are the remedies in each scenario?

Thank you,
dbuchanan
 
B

Bart Mermuys

Hi,
Bart,

I've followed these guidelines in my working application. However there
is an interesting yet serious glitch.

There is a slightly different glitch depending on how the combobox is
configured. The glitches are very specific so I will careful explain
them in separate sections below.
I'll name and describe these like this:
Glitch 1 - Occurs when the comboBox is configured using properties
window and the "ComboBox Tasks" box.

Try to change the order of fill and see if it helps, first load the parent
tables (lookup) then the child table (master). It looks like tbl020Version
is the master table so load it the last.
Glitch 2 - Occurs when the comboBox is configured using code only
(except that the control was dragged from the DataSouces window)

A modal Form can be re-opened after it's closed, so the Form_Load method can
run more then once, that's why you are getting "Binding already exists..."
You can setup the bindings insde the constructor (Sub New) after
InitializeComponents().

An alternative is to Dispose the modal Form after ShowDialog and create a
new one when you need to show it again.

Modeless Forms are Disposed when they are closed.

HTH,
Greetings

[code snipped].
 

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

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top