如何将枚举的格式化字符串描述绑定到组合框?我希望组合框显示说明,而不是枚举。
我有一个这样的枚举:
Public Enum Sandwiches
<ComponentModel.Description("Ham Sandwich")> HamSandwich
<ComponentModel.Description("Reuben")> Reuben
<ComponentModel.Description("Po’ Boy")> PoBoy
<ComponentModel.Description("Grilled Cheese")> GrilledCheese
End Enum
在描述字符串已绑定到组合框后,我可以使用此函数将所选项目转换回枚举:
Public Function GetEnumFromDescriptionAttribute(Of T)(description As String) As T
Dim type As Type = GetType(T)
If Not type.IsEnum Then
Throw New InvalidOperationException()
End If
For Each fi As Reflection.FieldInfo In type.GetFields()
Dim descriptionAttribute As ComponentModel.DescriptionAttribute = TryCast(Attribute.GetCustomAttribute(fi, GetType(ComponentModel.DescriptionAttribute)), ComponentModel.DescriptionAttribute)
If descriptionAttribute IsNot Nothing Then
If descriptionAttribute.Description <> description Then
Continue For
End If
Return DirectCast(fi.GetValue(Nothing), T)
End If
If fi.Name <> description Then
Continue For
End If
Return DirectCast(fi.GetValue(Nothing), T)
Next
Return Nothing
End Function
但我找不到一种干净的方法将所有枚举绑定到组合框。我知道一个经常建议的解决方案是将枚举和枚举描述转换为字典,然后将它们设置为 cbo DisplayMember 和 ValueMember。但我不知道如何真正做到这一点。
我已经准备好了几十个关于如何做到这一点的部分解决方案;问题是它们都是用 C# 编写的,在 Option Strict 关闭的情况下使用隐式转换,并且没有显示完整的实现。因此,我无法将任何解决方案转换为 .NET,因为我不知道已定义的类型变量是什么。
答案 0 :(得分:1)
这是我前段时间写的一个类,用于表示一个 Enum
值及其描述:
Imports System.ComponentModel
Imports System.Reflection
''' <summary>
''' Contains an enumerated constant value and a friendly description of that value, if one exists.
''' </summary>
''' <typeparam name="T">
''' The enumerated type of the value.
''' </typeparam>
Public Class EnumDescriptor(Of T)
''' <summary>
''' The friendly description of the value.
''' </summary>
Private _description As String
''' <summary>
''' The enumerated constant value.
''' </summary>
Private _value As T
''' <summary>
''' Gets the friendly description of the value.
''' </summary>
''' <value>
''' A <b>String</b> containing the value's Description attribute value if one exists; otherwise, the value name.
''' </value>
Public ReadOnly Property Description() As String
Get
Return Me._description
End Get
End Property
''' <summary>
''' Gets the enumerated constant value.
''' </summary>
''' <value>
''' An enumerated constant of the <b>EnumDescriptor's</b> generic parameter type.
''' </value>
Public ReadOnly Property Value() As T
Get
Return Me._value
End Get
End Property
''' <summary>
''' Creates a new instance of the <b>EnumDescriptor</b> class.
''' </summary>
''' <param name="value">
''' The value to provide a description for.
''' </param>
Public Sub New(ByVal value As T)
Me._value = value
'Get the Description attribute.
Dim field As FieldInfo = value.GetType().GetField(value.ToString())
Dim attributes As DescriptionAttribute() = DirectCast(field.GetCustomAttributes(GetType(DescriptionAttribute), _
False), _
DescriptionAttribute())
'Use the Description attribte if one exists, otherwise use the value itself as the description.
Me._description = If(attributes.Length = 0, _
value.ToString(), _
attributes(0).Description)
End Sub
''' <summary>
''' Overridden. Creates a string representation of the object.
''' </summary>
''' <returns>
''' The friendly description of the value.
''' </returns>
Public Overrides Function ToString() As String
Return Me.Description
End Function
End Class
这是我刚刚写的一个简化版本:
Imports System.ComponentModel
Imports System.Reflection
Public Class EnumDescriptor(Of T)
Public ReadOnly Property Description As String
Public ReadOnly Property Value As T
Public Sub New(value As T)
Me.Value = value
'Get the Description attribute.
Dim field = value.GetType().GetField(value.ToString())
Dim attributes = DirectCast(field.GetCustomAttributes(GetType(DescriptionAttribute), False), DescriptionAttribute())
'Use the Description attribute if one exists, otherwise use the value itself as the description.
Description = If(attributes.Length = 0, value.ToString(), attributes(0).Description)
End Sub
Public Overrides Function ToString() As String
Return Description
End Function
End Class
这是另一个类,可用于为 Enum
中的每个值存储前一个类的实例:
''' <summary>
''' A collection of EnumDescriptors for an enumerated type.
''' </summary>
''' <typeparam name="T">
''' The type of the enumeration for which the EnumDescriptors are created.
''' </typeparam>
Public Class EnumDescriptorCollection(Of T)
Inherits ObjectModel.Collection(Of EnumDescriptor(Of T))
''' <summary>
''' Creates a new instance of the <b>EnumDescriptorCollection</b> class.
''' </summary>
Public Sub New()
'Populate the collection with an EnumDescriptor for each enumerated value.
For Each value As T In [Enum].GetValues(GetType(T))
Items.Add(New EnumDescriptor(Of T)(value))
Next
End Sub
End Class
以下是将集合类的实例绑定到 ComboBox
的一些示例用法:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
With ComboBox1
.DisplayMember = "Description"
.ValueMember = "Value"
.DataSource = New EnumDescriptorCollection(Of Sandwiches)
End With
End Sub
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
MessageBox.Show(ComboBox1.SelectedValue.ToString(), ComboBox1.Text)
End Sub
End Class
答案 1 :(得分:1)
您的目标似乎是覆盖 Enum 值的字符串表示形式。基本表示显示 Enum 的名称,而您希望显示 Enum 的描述属性。
假设这是一个 WinForm 的组合框,标准的方法是用自定义的 TypeConverter 装饰 Enum 并覆盖 ConvertTo
方法。使用 EnumConverter Class 和自定义转换器的基础可以最大限度地减少所需的代码。
Imports System.ComponentModel
Imports System.Globalization
Imports System.Reflection
Public Class EnumDescriptionConverter(Of T As {Structure, IConvertible}) : Inherits EnumConverter
Private enumDescriptions As New Dictionary(Of T, String)
Public Sub New()
MyBase.New(GetType(T))
' Since the ability to add an Enum constraint to the generic type does not exist in VB.
' this check is to ensure that it is an Enum.
' Note that normally, throwing an exception in a constructor is considered bad form, but
' there is no other option
If GetType(T).IsEnum Then
LoadEnumDescriptions()
Else
Throw New ArgumentException($"{GetType(T).Name} is not an Enum")
End If
End Sub
Private Sub LoadEnumDescriptions()
' An Enum type comprises static (Shared) fields that represent the defined enum values and
' an instance field that holds thae actual value. so only retrieve the static fields
' to get the defined (named) enum members.
For Each fi As FieldInfo In GetType(T).GetFields(BindingFlags.Public Or BindingFlags.Static)
Dim description As String
Dim descAttrib As DescriptionAttribute = fi.GetCustomAttribute(Of DescriptionAttribute)
If descAttrib Is Nothing Then
' no description attribute so use the defined name
description = fi.Name
Else
description = descAttrib.Description
End If
enumDescriptions.Add(CType(fi.GetValue(Nothing), T), description)
Next
End Sub
Public Overrides Function ConvertTo(context As ITypeDescriptorContext, culture As CultureInfo, value As Object, destinationType As Type) As Object
Dim ret As Object
' the purpose of this converter is to provide an enum's description attribute as the string representation
' instead of the field name as provided by the standard implemention.
If destinationType Is GetType(String) AndAlso value IsNot Nothing Then
Dim enumValue As T = DirectCast(value, T)
If enumDescriptions.ContainsKey(enumValue) Then
ret = enumDescriptions(enumValue)
Else
ret = enumValue.ToString(Nothing)
End If
Else
ret = MyBase.ConvertTo(context, culture, value, destinationType)
End If
Return ret
End Function
End Class
修改您的 Enum 定义以使用此自定义转换器。
<TypeConverter(GetType(EnumDescriptionConverter(Of Sandwiches)))>
Public Enum Sandwiches
<ComponentModel.Description("Ham Sandwich")> HamSandwich
<ComponentModel.Description("Reuben")> Reuben
<ComponentModel.Description("Po’ Boy")> PoBoy
<ComponentModel.Description("Grilled Cheese")> GrilledCheese
End Enum
现在您需要做的就是使用枚举值加载 ComboBox.Items
。
ComboBox1.Items.AddRange(System.Enum.GetValues(GetType(Sandwiches)).Cast(Of Object).ToArray())
使用 ComboBox.SelectedItem
检索选定的值。