I have bound a ComboBox to an enum like so
Enum Foo
Bar
Baz
End Enum
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Particularly when the values are not sequential, you need to provide a way for the control to "map" the Name to the related value. Once you post Enum.GetValues
or the Names to a CBO, they have become detached.
You can use something like a KeyValuesPair(of String, Int32)
using the names as TKey and the values as TValue. The generic can make it seem more complex than it is. Since the key will always be String
, and the value is usually an Int32
I tend to use a simple NameValuePair
class for these:
Public Class NameValuePair
Public Property Name As String
Public Property Value As Int32
Public Sub New(n As String, v As Int32)
Name = n
Value = v
End Sub
Public Overrides Function ToString() As String
Return String.Format("{0}", Name)
End Function
End Class
That will associate any name with any value. The main thing is that you control what displays for ToString()
. In this case, both the name and value come from an Enum; a simple method to create a List or Array of them:
Private Enum Stooges
Moe = 9
Larry = 99
Curly = 45
Shemp = 65
CurlyJoe = 8
End Enum
' method to convert any Enum to a collection of Named-Value pairs
Private Function EnumToPairsList(e As Type) As List(Of NameValuePair)
Dim ret As New List(Of NameValuePair)
Dim vals = [Enum].GetValues(e)
Dim names = [Enum].GetNames(e).ToArray
For n As Int32 = 0 To names.Count - 1
ret.Add(New NameValuePair(names(n), CType(vals.GetValue(n), Int32)))
Next
Return ret
End Function
EnumsToPairsList
could return an array, or use KeyValuePair
as desired. It can be expanded to use a Description
in place of the name when present. Using it:
cbox1.DataSource = EnumToPairsList(GetType(Stooges))
cbox1.DisplayMember = "Name" ' use "Key" for a KVP
cbox1.ValueMember = "Value"
' set a value:
cbox1.SelectedValue = Convert.ToInt32(Stooges.Shemp)
Since you have "wrapped" the enum in the NVP class, that is what each SelectedItem
will be (enclosed in an Object
). When using a DataSource
such as this, you would typically act in the SelectedValueChanged
event and examine the SelectedValue
. This is the main purpose of it: show the names to the user, but return the enum value to you in code.
The only "trick" is that it needs to be cast back to your enum:
Private Sub cbox1_SelectedValueChanged(...
Dim eItem As Stooges = CType(cbox1.SelectedValue, Stooges)
Console.WriteLine(eItem)
Console.WriteLine(eItem.ToString)
45
Curly
If you insist on using SelectedItem
, you will have to cast from Object
to NameValuePair
, get the Value, then cast that to your Enum Type.
It is often useful to hold onto a copy of the data source so it resides somewhere other than only as a control datasource:
Private StoogesDS As List(Of NameValuePair)
...
StoogesDS = EnumsToPairsList(GetType(Stooges))
cbox1.DataSource = StoogesDS
This allows your code to still use the collection even when the form is not around. As noted above, each item is now a NameValuePair
object.
cbox1.SelectedItem = StoogesDS.FirstOrDefault(Function(z) z.Name = Stooges.Shemp.ToString())