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)
Using It
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())
SelectedIndex
to achieve the desired effect, but that's because, by coincidence, the index of the items match the enum values. What happens when the enum values are different to the index? – TobyFooComboBox.SelectedItem = Foo.Bar
When they are not simple {0,1,2} values, use a Type to set both the Value and Displaymember – Ňɏssa Pøngjǣrdenlarp