2

I want to fill a combobox from a dictionary source. This dictionary has a class value and I want to use the class properties for combobox values.

Example class

Public Class Customer
    Public ID As Integer
    Public Name As String
    Public Address As String
    Public City As String

    Public Sub New(ByVal newID As Integer, ByVal newName As String, ByVal newAddress As String, ByVal newCity As String)
        ID = newID
        Name = newName
        Address = newAddress
        City = newCity
    End Sub
End Class

Example form

Public Class Form1
    Dim Customers As New Dictionary(Of Integer, Customer)

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Customers.Add(341, New Customer(341, "Michael", "Street 52", "New York"))
        Customers.Add(149, New Customer(149, "Susan", "Street 12", "Los Angelos"))
        Customers.Add(721, New Customer(721, "Bill", "Street 98", "Houston"))
        Customers.Add(958, New Customer(958, "Jeff", "Street 54", "Washington"))

        ComboBox1.DataSource = Customers 'What to use as a datasource??
        ComboBox1.DisplayMember = "Name"
        ComboBox1.ValueMember = "ID"
    End Sub

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        MsgBox(ComboBox1.SelectedValue)
    End Sub
End Class

How to set the ComboBox1 properties so that I can see the customer name as DisplayMember and it's ID as ValueMember?

Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
Martin
  • 1,184
  • 8
  • 24
  • Can you just set the `DataSource` to `Customers.Values` and then the `DisplayMember` and `ValueMember` as normal? – Jeff B Nov 09 '15 at 17:33

1 Answers1

5

When binding to a Dictionary, things get a little...'indirect'.

Unlike a List(Of T), a dictionary does not have the interfaces required for use as a DataSource. For that, you need to use a BindingSource.

' NVP is a NameValuePair class I had on hand
Private NamedPairs As New Dictionary(Of Integer, NVP)
...
NamedPairs.Add(341, New NVP("Michael", 341))
NamedPairs.Add(149, New NVP("Susan", 149))
NamedPairs.Add(721, New NVP("Bill", 721))
NamedPairs.Add(958, New NVP("Jeff", 958))

ComboBox1.DataSource = New BindingSource(NamedPairs, Nothing)
ComboBox1.DisplayMember = "Value"
ComboBox1.ValueMember = "Key"

Also unlike a list, where there are Customer items in the list, inside the dictionary are a set of KeyValuePair(Of TK, TV). So that is what you use for the DisplayMember and ValueMember properties.

The last step is to perhaps change your Customer class to control what displays. Since you cannot map to an actual/specific Customer property, the default display may be something like WindowsApp17.Foo.Customer. To display something more worthwhile, you need to override ToString():

Class Customer
    ...
    Public Overrides Function ToString() As String
        Return Name
    End Function

You can have it display whatever you want:

Return String.Format("{0} ({1})", Name, Value.ToString)
' or
Return String.Format("{0} from ({1})", FirstName, City)

Private Sub ComboBox1_SelectedIndexChanged(sender ...
    Console.WriteLine("SelectedValue: {0}  ", ComboBox1.SelectedValue)
End Sub

Output:

SelectedValue: 721

SelectedItem will be the entire KVP as Object, so cast it back:

Dim kvp As KeyValuePair(Of Int32, Customer) = CType(cbo1.SelectedItem,
                 KeyValuePair(Of Int32, Customer))
Dim thisCust As Customer = kvp.Value
Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
  • How to update bindings and display updated combobox if the dictionary changed? Is the solution for the following question the only way to do it? https://stackoverflow.com/questions/8688724/how-to-store-a-list-of-objects-in-application-settings – DrMarbuse Apr 13 '22 at 12:57