How to set SelectedValue for Enum bound ComboBox

后端 未结 1 1245
粉色の甜心
粉色の甜心 2020-12-21 10:04

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
            


        
相关标签:
1条回答
  • 2020-12-21 10:39

    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())
    
    0 讨论(0)
提交回复
热议问题