【问题标题】:How to set SelectedValue for Enum bound ComboBox如何为枚举绑定 ComboBox 设置 SelectedValue
【发布时间】:2016-08-18 16:19:42
【问题描述】:

我已经将一个 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.Windows.Forms.dll 中出现“System.InvalidOperationException”类型的未处理异常

附加信息:无法在具有空 ValueMember 的 ListControl 中设置 SelectedValue。

检查 ComboBox 我确实可以看到 ValueMember 属性为空。但是SelectedValue is 等于我阅读它时当前选定项目的预期值,这表明ValueMember is 设置为枚举值预计。

A)如果ValueMember属性没有设置,SelectedValue中的值是从哪里来的?

B) 如果绑定导致SelectedValue 包含正确的值,为什么翻转设置不以同样的方式工作?

C) 我还需要做什么才能使这个该死的 .Net 正常工作?

请注意,确实有很多关于此的 C# 和 WPF 问题,据我所见,没有一个能真正解释这一点,而且我无法从答案建议他们。

【问题讨论】:

  • 我可以使用SelectedIndex 来达到预期的效果,但是这是因为巧合的是,项目的索引与枚举值匹配。当枚举值与索引不同时会发生什么?
  • FooComboBox.SelectedItem = Foo.Bar 当它们不是简单的 {0,1,2} 值时,使用 Type 来设置 Value 和 Displaymember
  • @Plutonix,如何“使用 Type 设置 Value 和 DisplayMember”?
  • 有Assigning a value to ComboBox Items使用Enum.Names和ENum.Values;还有Set DisplayMember and ValueMember on ComboBox without DataSource,这使得它比“无数据源”要求更复杂
  • 啊,你的意思是使用复杂类型的集合并绑定到那个......对于一个简单的简短、常量、数字列表来说有点多,不是吗?天哪,我讨厌 VB。

标签: .net vb.net combobox enums


【解决方案1】:

特别是当值不是连续的时,您需要为控件提供一种将名称“映射”到相关值的方法。一旦您将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() 的显示内容。在这种情况下,名称和值都来自枚举;创建它们的列表或数组的简单方法:

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,获取值,然后将that 转换为您的枚举类型。


保留数据源的副本通常很有用,因此它驻留在某个位置,而不仅仅是作为控制数据源:

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())

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-07
    相关资源
    最近更新 更多