sergiu reznicencu sergiu reznicencu - 5 months ago 72
Vb.net Question

Update bindingSource used for combobox

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


b.Add(1, "a")
b.Add(2, "b")


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"
End Sub

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
''a.ResetBindings(False)
End Sub
End Class



This is how it looks:


enter image description here



When I de-comment the DisplayMember and ValueMember properties of the comboboxes this is what happens(and after pressing Button1):


enter image description here

As you can see the count property says there are 2 items but the DataSource says there are 3. I think that's why the new-added item doesn't appear (when I press Button1 the new element is not being added despite the fact it is stored in the BindingSource).

Where is the problem?


Note: I found something maybe useful on MSDN but it's not quite working (I updated the code according to this page).

Answer

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 DataSource:

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 Display- and 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"))
  • cboBS is the BindingSource for the Combo
  • DictionaryEntry is the Type which holds each entry in a HashTable.

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

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

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.

Comments