For a long time now I have been trying to fix a problem with a combobox (it givs me headaches when I think at how many tests and forums I've tried). I know that after a combobox has been "binded" to a source it will be synchronised with it(every change will appear in combobox).
Here's my simple testing code:
Public Class Form1
Dim a As New BindingSource, b As New Hashtable
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ComboBox1.DataSource = a
ComboBox2.DataSource = a
a.DataSource = b
a.DataMember = "Value"
'' Tried this when a.DataMember is commented .Otherwise it gives error
''ComboBox1.DisplayMember = "Value"
''ComboBox1.ValueMember = "Key"
''ComboBox2.DisplayMember = "Value"
''ComboBox2.ValueMember = "Key"
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
b.Add(3, "c") ''Nothing new in the combobox
I know that after a combobox has been "binded" to a source it will be synchronised with it(every change will appear in combobox).
The problem is that your understanding is not entirely true. You need to use a special collection for changes to the contents to automatically show up in the control. If the contents of the collection is a Type (Class), changes to one of the properties will not automatically show up without another special step.
The ham-fisted way to overcome this is to "rebind" the
cbox.DataSource = Nothing ht.Add(0, "Zulu") cbox.DataSource = New BindingSource(ht, Nothing) cbox.DisplayMember = "Value" cbox.ValueMember = "Key"
This rebuilds the
BindingSource (or builds a new one in this case) so it can "see" the new entry. The
ValueMember values are lost, so you have to reset those. "Rebinding" can also cause problems with something like a
ListBox because any previous selections will be lost.
There is a way built into the
BindingSource which does the opposite:
cboBS.Add(New DictionaryEntry(0, "Zulu"))
BindingSourcefor the Combo
DictionaryEntryis the Type which holds each entry in a
Now, the new entry shows up and is in the
BindingSource, but it is not in your underlying collection. You could work with this: use a temp collection to initialize the
BindingSource and thereafter use the
BindingSource as the collection. It is not what it is meant to do, so I doubt I'd ever actually use it.
The problem with most collections is that they are not signaling when and item is added or deleted. Most collections are like this and the
BindingSource cant solve it.
Your best bet may be to use a
BindingList(Of T). (This wont enforce the unique key constraint if the
HashTable, just check to see if the value has been added - you need to do that anyway with a
HashTable to avoid Exceptions.) Another thing which will work - but may seem odd - is a
Private BList As BindingList(Of NameValuePair) ... BList = New BindingList(Of NameValuePair) BList.Add(New NameValuePair("Alpha", 1)) BList.Add(New NameValuePair("Delta", 4)) BList.Add(New NameValuePair("Gamma", 3)) BList.Add(New NameValuePair("Beta", 2)) cbox.DataSource = BList cbox.DisplayMember = "Name" cbox.ValueMember = "Value"
You no longer need a
BindingSource. NameValuePair is a simple utility class found here to associate a
Value with a 'Name'. You could also use a
KeyValuePair(Of TK, TV).
Adding a member to the list, requires no extra step and no rebinding. It automatically shows. However, if you change a property on an item in the list:
myPersonList(0).Name = "Ziggy"
...these changes will not show up unless the underlying class implements
The link above approaches the question differently: Assigning a value to ComboBox Items and may also be helpful.
The blog entry listed in the comment is pretty good too. It also covers a bit about other collections and use cases with some info in the Whys and Wherefores.