如何为Enum绑定的ComboBox

时间:2016-08-18 16:19:42

标签: .net vb.net combobox enums

我已将ComboBox绑定到类似的枚举

Enum Foo
    Bar
    Baz
End Enum

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    FooComboBox.DataSource = [Enum].GetValues(GetType(Foo))
End Sub

我想在给定时间更改所选值

Private Sub FooBar()
    FooComboBox.SelectedValue = Foo.Bar
End Sub

但这引发了一个例外:

  

未处理的类型' System.InvalidOperationException'发生在System.Windows.Forms.dll

中      

其他信息:无法在ListControl中使用空ValueMember设置SelectedValue。

检查ComboBox我确实可以看到ValueMember属性为空。但是SelectedValue 等于我读取时当前所选项目的预期值,这表示ValueMember 设置为枚举值与预期一致。

A)如果未设置ValueMember属性,SelectedValue中的值来自何处?

B)如果绑定导致SelectedValue包含正确的值,为什么翻盖不能以相同的方式设置它?

C)我还需要做些什么来使这个血腥的.Net工作?

请注意,确实有不少C#&关于这一点的WPF问题,没有人真正解释这一点,就我所看到的而言,我还没有能够根据建议的答案找出正确的vb语法。

1 个答案:

答案 0 :(得分:3)

特别是当值不是连续的时,您需要为控件提供一种方法,将Name“映射”到相关值。将Enum.GetValues或姓名发布到CBO后,它们就会脱离。

您可以使用KeyValuesPair(of String, Int32)之类的名称作为TKey,将值作为TValue使用。通用可以使它看起来比它复杂。由于密钥始终为String,而值通常为 Int32,因此我倾向于使用简单的NameValuePair类:

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

这会将任何名称与任何值相关联。主要是你控制ToString()的显示。在这种情况下,名称和值都来自Enum;一种创建List或Array数组的简单方法:

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可以返回数组,也可以根据需要使用KeyValuePair。它可以扩展为使用Description代替名称(如果存在)。使用它:

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)

使用它

由于您已在NVP类中“包装”枚举,因此每个SelectedItem将包含在Object中。使用此类DataSource时,您通常会在SelectedValueChanged事件中执行操作并检查SelectedValue。这是它的主要目的:向用户显示名称,但在代码中将枚举值返回给您。

唯一的“诀窍”是它需要被回流到你的枚举:

Private Sub cbox1_SelectedValueChanged(...
    Dim eItem As Stooges = CType(cbox1.SelectedValue, Stooges)
    Console.WriteLine(eItem)
    Console.WriteLine(eItem.ToString)        
  

45
    卷曲

如果您坚持使用SelectedItem,则必须从Object投射到NameValuePair,获取值,然后将 投射到您的枚举类型。

保留数据源的副本通常很有用,因此它位于除了作为控制数据源之外的其他位置:

Private StoogesDS As List(Of NameValuePair)
...
StoogesDS = EnumsToPairsList(GetType(Stooges))
cbox1.DataSource = StoogesDS

这允许您的代码即使在表单不在时也仍然使用该集合。如上所述,每个项目现在都是NameValuePair对象。

cbox1.SelectedItem = StoogesDS.FirstOrDefault(Function(z) z.Name = Stooges.Shemp.ToString())