1

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

Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
sergiu reznicencu
  • 1,039
  • 1
  • 11
  • 31

1 Answers1

2

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

The ham-fisted way to overcome this is to "reset" 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. "Resetting" 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 depending on the underlying collection:

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 HashTable. The new item will get added to something like a List<T> (a HashSet<T> would be a better choice than HashTable).


The problem with most collections is that they do not signal when and item is added or deleted. Most collections are like this and the BindingSource can't 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 am item 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.

Community
  • 1
  • 1
Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
  • Blog at https://blogs.msdn.microsoft.com/dchandnani/2005/03/15/bindingsource-a-closer-look/ led me to a similar solution. Your's is much more in depth than what I would have written though. +1 – topshot Jun 28 '16 at 22:49