将枚举绑定到WinForms组合框,然后进行设置


122

许多人回答了如何将枚举绑定到WinForms中的组合框的问题。就像这样:

comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));

但是,如果无法设置要显示的实际值,那将毫无用处。

我努力了:

comboBox1.SelectedItem = MyEnum.Something; // Does not work. SelectedItem remains null

我也尝试过:

comboBox1.SelectedIndex = Convert.ToInt32(MyEnum.Something); // ArgumentOutOfRangeException, SelectedIndex remains -1

有谁知道如何做到这一点?


2
为什么不试试ComboBox.SelectedValue呢?
奥利弗·弗里德里希

5
如果您的问题已得到回答,您应该选择一个答案。
Ryan The Leach 2013年

数据绑定枚举的要点还不太清楚。枚举在运行时可能不会更改。您还可以编写一个扩展方法,该方法将用枚举的所有值填充组合框的items集合。
Andreas


@OliverFriedrich SelectedValue导致InvalidOperationException我。“不能设置SelectedValueListControl一个空的ValueMember。”
泰勒

Answers:


161

枚举

public enum Status { Active = 0, Canceled = 3 }; 

从中设置下拉值

cbStatus.DataSource = Enum.GetValues(typeof(Status));

从所选项目中获取枚举

Status status; 
Enum.TryParse<Status>(cbStatus.SelectedValue.ToString(), out status); 

5
谢谢,这对我有用。请记住,tryparse是.net 4.0语句。
real_yggdrasil 2012年

对我来说,SelectedValue始终为null。看来组合框没有被初始化。(myEnum)this.GridView.CurrentRow.Cells [“ comboColumnCell”]。Value。我可以看到值,但在内部它会抛出空指针异常
ssal

3
这正是OP不想使用的方式。问题在于,在每个值的代码中都向用户显示了名称,该名称需要重构,而且大多数时候都不方便用户使用。
亚历杭德罗(Alejandro)2014年

5
为什么使用TryParse而不是Parse?... var status(Status)Enum.Parse(typeof(Status),cbStatus.SelectedValue.ToString()); ...将枚举绑定到组合框,因此您知道该值必须是有效的枚举值,如果那不是什么大错了,您可能想要例外。
bytedev

1
为什么这被遗忘?问题是如何使用枚举值之一以编程方式设置组合框的选定值。
泰勒

39

为了简化:

首先初始化此命令:(例如之后InitalizeComponent()

yourComboBox.DataSource =  Enum.GetValues(typeof(YourEnum));

要检索组合框上的选定项目:

YourEnum enum = (YourEnum) yourComboBox.SelectedItem;

如果要为组合框设置值:

yourComboBox.SelectedItem = YourEnem.Foo;

2
只要“显示”值与“值”成员相同,此方法就起作用,否则不起作用。
剧本之王

15

代码

comboBox1.SelectedItem = MyEnum.Something;

可以,问题必须存在于DataBinding中。DataBinding分配发生在构造函数之后,主要是第一次显示组合框。尝试在Load事件中设置值。例如,添加以下代码:

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    comboBox1.SelectedItem = MyEnum.Something;
}

并检查是否有效。


12

尝试:

comboBox1.SelectedItem = MyEnum.Something;

编辑:

糟糕,您已经尝试过了。但是,当我的comboBox设置为DropDownList时,它对我有用。

这是我的完整代码(适用于DropDown和DropDownList):

public partial class Form1 : Form
{
    public enum BlahEnum
    { 
        Red,
        Green,
        Blue,
        Purple
    }

    public Form1()
    {
        InitializeComponent();

        comboBox1.DataSource = Enum.GetValues(typeof(BlahEnum));

    }

    private void button1_Click(object sender, EventArgs e)
    {
        comboBox1.SelectedItem = BlahEnum.Blue;
    }
}

有趣的是,您可以执行comboBox1.SelectedItem = BlahEnum.Blue;这很高兴,但是如果您希望组合框中的内容为字符串,例如,组合框中的某项为“可咀嚼的维生素丸”,该怎么办?
barlop

11

假设您有以下枚举

public enum Numbers {Zero = 0, One, Two};

您需要一个将这些值映射到字符串的结构:

public struct EntityName
{
    public Numbers _num;
    public string _caption;

    public EntityName(Numbers type, string caption)
    {
        _num = type;
        _caption = caption;
    }

    public Numbers GetNumber() 
    {
        return _num;
    }

    public override string ToString()
    {
        return _caption;
    }
}

现在返回一个对象数组,其中所有枚举都映射到一个字符串:

public object[] GetNumberNameRange()
{
    return new object[]
    {
        new EntityName(Number.Zero, "Zero is chosen"),
        new EntityName(Number.One, "One is chosen"),
        new EntityName(Number.Two, "Two is chosen")
    };
}

并使用以下命令填充您的组合框:

ComboBox numberCB = new ComboBox();
numberCB.Items.AddRange(GetNumberNameRange());

创建一个函数以检索枚举类型,以防万一您想将其传递给函数

public Numbers GetConversionType() 
{
    EntityName type = (EntityName)numberComboBox.SelectedItem;
    return type.GetNumber();           
}

然后你应该没问题:)


+1个不错的解决方案。最近遇到了这个问题,并以类似的方式解决了(只是用一个Tuple代替)。我会将枚举值和描述都转换为属性,然后添加numberCB.DisplayProperty = "Caption";`,numberCB.ValueProperty = "Num"以便您可以SelectedValue直接使用并绑定到它。
亚历杭德罗(Alejandro)2014年

恕我直言,也许是更完整的示例源代码,如果还有的话,还可以在ComboBox中添加“全部” /“全选”选项,以过滤搜索中的所有行。
Kiquenet 2014年

5

试试这个:

// fill list
MyEnumDropDownList.DataSource = Enum.GetValues(typeof(MyEnum));

// binding
MyEnumDropDownList.DataBindings.Add(new Binding("SelectedValue", StoreObject, "StoreObjectMyEnumField"));

StoreObject是我的对象示例,具有StoreMyEnum值的StoreObjectMyEnumField属性。


1
到目前为止,这是最好的方法,但它对我没有用。我不得不使用“ SelectedItem”而不是“ SelectedValue”
Tiago Freitas Leal

4
 public static void FillByEnumOrderByNumber<TEnum>(this System.Windows.Forms.ListControl ctrl, TEnum enum1, bool showValueInDisplay = true) where TEnum : struct
    {
        if (!typeof(TEnum).IsEnum) throw new ArgumentException("An Enumeration type is required.", "enumObj");

        var values = from TEnum enumValue in Enum.GetValues(typeof(TEnum))
                     select
                        new
                         KeyValuePair<TEnum, string>(   (enumValue), enumValue.ToString());

        ctrl.DataSource = values
            .OrderBy(x => x.Key)

            .ToList();

        ctrl.DisplayMember = "Value";
        ctrl.ValueMember = "Key";

        ctrl.SelectedValue = enum1;
    }
    public static void  FillByEnumOrderByName<TEnum>(this System.Windows.Forms.ListControl ctrl, TEnum enum1, bool showValueInDisplay = true  ) where TEnum : struct
    {
        if (!typeof(TEnum).IsEnum) throw new ArgumentException("An Enumeration type is required.", "enumObj");

        var values = from TEnum enumValue in Enum.GetValues(typeof(TEnum))
                     select 
                        new 
                         KeyValuePair<TEnum,string> ( (enumValue),  enumValue.ToString()  );

        ctrl.DataSource = values
            .OrderBy(x=>x.Value)
            .ToList();

        ctrl.DisplayMember = "Value";
        ctrl.ValueMember = "Key";

        ctrl.SelectedValue = enum1;
    }

你什么意思 ?我不明白你的评论。此扩展方法有效
Mickey Perlstein 2014年

这取决于您的枚举数是否允许OR标志。如果是这样,您可以添加一个名为255的名为All的标志,并以All作为enum1调用该函数,这将创建默认值。即comboBox1.FillByEnumOrderByName(MyEnum.All)
米奇·

像这样的任何选项:var l = values.OrderBy(x => x.Value).ToList(); l.Insert(0,“全部”);
Kiquenet 2014年

我的枚举是枚举A {鸭= 0,天鹅= 1,小丑= 3};您的系统不适用于我的情况。
米奇·佩尔斯坦

3

这是在组合框中加载枚举项的解决方案:

comboBox1.Items.AddRange( Enum.GetNames(typeof(Border3DStyle)));

然后将枚举项用作文本:

toolStripStatusLabel1.BorderStyle = (Border3DStyle)Enum.Parse(typeof(Border3DStyle),comboBox1.Text);

3

根据@Amir Shenouda的回答,我得出以下结论:

枚举的定义:

public enum Status { Active = 0, Canceled = 3 }; 

从中设置下拉值:

cbStatus.DataSource = Enum.GetValues(typeof(Status));

从所选项目获取枚举:

Status? status = cbStatus.SelectedValue as Status?;

2
为什么使用可空值?您可以使用显式强制转换(括号强制转换),而不能使用可为空
John Demetriou

2
public Form1()
{
    InitializeComponent();
    comboBox.DataSource = EnumWithName<SearchType>.ParseEnum();
    comboBox.DisplayMember = "Name";
}

public class EnumWithName<T>
{
    public string Name { get; set; }
    public T Value { get; set; }

    public static EnumWithName<T>[] ParseEnum()
    {
        List<EnumWithName<T>> list = new List<EnumWithName<T>>();

        foreach (object o in Enum.GetValues(typeof(T)))
        {
            list.Add(new EnumWithName<T>
            {
                Name = Enum.GetName(typeof(T), o).Replace('_', ' '),
                Value = (T)o
            });
        }

        return list.ToArray();
    }
}

public enum SearchType
{
    Value_1,
    Value_2
}

恕我直言,也许是更完整的示例源代码,如果还有的话,还可以在ComboBox中添加“全部” /“全选”选项,以过滤搜索中的所有行。
Kiquenet 2014年


1

我使用以下辅助方法,您可以将其绑定到列表。

    ''' <summary>
    ''' Returns enumeration as a sortable list.
    ''' </summary>
    ''' <param name="t">GetType(some enumeration)</param>
    Public Shared Function GetEnumAsList(ByVal t As Type) As SortedList(Of String, Integer)

        If Not t.IsEnum Then
            Throw New ArgumentException("Type is not an enumeration.")
        End If

        Dim items As New SortedList(Of String, Integer)
        Dim enumValues As Integer() = [Enum].GetValues(t)
        Dim enumNames As String() = [Enum].GetNames(t)

        For i As Integer = 0 To enumValues.GetUpperBound(0)
            items.Add(enumNames(i), enumValues(i))
        Next

        Return items

    End Function

1

将枚举转换为字符串列表,并将其添加到comboBox

comboBox1.DataSource = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>();

使用selectedItem设置显示的值

comboBox1.SelectedItem = SomeEnum.SomeValue;

1

这些都不对我有用,但是这样做了(它的另一个好处是能够更好地描述每个枚举的名称)。我不确定这是否是由于.net更新引起的,但是不管我认为这是最好的方法。您需要添加对以下内容的引用:

使用System.ComponentModel;

enum MyEnum
{
    [Description("Red Color")]
    Red = 10,
    [Description("Blue Color")]
    Blue = 50
}

....

    private void LoadCombobox()
    {
        cmbxNewBox.DataSource = Enum.GetValues(typeof(MyEnum))
            .Cast<Enum>()
            .Select(value => new
            {
                (Attribute.GetCustomAttribute(value.GetType().GetField(value.ToString()), typeof(DescriptionAttribute)) as DescriptionAttribute).Description,
                value
            })
            .OrderBy(item => item.value)
            .ToList();
        cmbxNewBox.DisplayMember = "Description";
        cmbxNewBox.ValueMember = "value";
    }

然后,当您要访问数据时,请使用以下两行:

        Enum.TryParse<MyEnum>(cmbxNewBox.SelectedValue.ToString(), out MyEnum proc);
        int nValue = (int)proc;

1

在其他所有响应中,这可能永远都看不到,但这是我想出的代码,它的好处是可以使用DescriptionAttributeif存在(如果存在),否则可以使用enum值本身的名称。

我使用字典是因为它具有现成的键/值项模式。一个List<KeyValuePair<string,object>>也可以工作,并且不需要不必要的哈希,但是字典可以使代码更简洁。

我得到的成员具有个MemberTypeField并且是字面的。这将创建一个仅包含枚举值的成员的序列。这是可靠的,因为枚举不能具有其他字段。

public static class ControlExtensions
{
    public static void BindToEnum<TEnum>(this ComboBox comboBox)
    {
        var enumType = typeof(TEnum);

        var fields = enumType.GetMembers()
                              .OfType<FieldInfo>()
                              .Where(p => p.MemberType == MemberTypes.Field)
                              .Where(p => p.IsLiteral)
                              .ToList();

        var valuesByName = new Dictionary<string, object>();

        foreach (var field in fields)
        {
            var descriptionAttribute = field.GetCustomAttribute(typeof(DescriptionAttribute), false) as DescriptionAttribute;

            var value = (int)field.GetValue(null);
            var description = string.Empty;

            if (!string.IsNullOrEmpty(descriptionAttribute?.Description))
            {
                description = descriptionAttribute.Description;
            }
            else
            {
                description = field.Name;
            }

            valuesByName[description] = value;
        }

        comboBox.DataSource = valuesByName.ToList();
        comboBox.DisplayMember = "Key";
        comboBox.ValueMember = "Value";
    }


}

0
comboBox1.SelectedItem = MyEnum.Something;

应该可以正常工作...您怎么知道它SelectedItem为null?


我可以在调试器中检查它。我认为这是因为SelectedItem的类型是对象,即引用类型,而枚举是值类型。尽管我本来希望编译器能够做到这一点。

0

您可以使用“ FindString ..”函数:

Public Class Form1
    Public Enum Test
        pete
        jack
        fran
        bill
    End Enum
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ComboBox1.DataSource = [Enum].GetValues(GetType(Test))
        ComboBox1.SelectedIndex = ComboBox1.FindStringExact("jack")
        ComboBox1.SelectedIndex = ComboBox1.FindStringExact(Test.jack.ToString())
        ComboBox1.SelectedIndex = ComboBox1.FindStringExact([Enum].GetName(GetType(Test), Test.jack))
        ComboBox1.SelectedItem = Test.bill
    End Sub
End Class

0

您可以将KeyValuePair值列表用作组合框的数据源。您将需要一个辅助方法,您可以在其中指定枚举类型并返回IEnumerable>,其中int是枚举的值,而string是枚举值的名称。在您的组合框中,将DisplayMember属性设置为“键”,将ValueMember属性设置为“值”。值和键是KeyValuePair结构的公共属性。然后,当像您一样将SelectedItem属性设置为枚举值时,它应该起作用。


0

目前,我正在使用Items属性而不是DataSource,这意味着我必须为每个枚举值调用Add,但是它是一个小的枚举,以及它的临时代码。

然后,我可以对值进行Convert.ToInt32并使用SelectedIndex进行设置。

临时解决方案,但暂时不使用YAGNI。

为这些想法加油打气,在获得一轮客户反馈后,当我制作适当的版本时,我可能会使用它们。



0
comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));

comboBox1.SelectedIndex = (int)MyEnum.Something;

comboBox1.SelectedIndex = Convert.ToInt32(MyEnum.Something);

这两项对我都有效,您确定没有其他问题吗?


2
不确定使用自定义枚举值是否可以正常工作,即enum MyEnum { Something = 47 }
Samantha Branham

0

将枚举设置为下拉列表的数据源的通用方法

显示将是名称。选择的值将是枚举本身

public IList<KeyValuePair<string, T>> GetDataSourceFromEnum<T>() where T : struct,IConvertible
    {
        IList<KeyValuePair<string, T>> list = new BindingList<KeyValuePair<string, T>>();
        foreach (string value in Enum.GetNames(typeof(T)))
        {
            list.Add(new KeyValuePair<string, T>(value, (T)Enum.Parse(typeof(T), value)));
        }
        return list;
    }

0

那总是一个问题。如果您有一个排序的枚举,例如从0到...

public enum Test
      one
      Two
      Three
 End

您可以将名称绑定到组合框,而不是使用.SelectedValue属性使用.SelectedIndex

   Combobox.DataSource = System.Enum.GetNames(GetType(test))

Dim x as byte = 0
Combobox.Selectedindex=x

0

在Framework 4中,您可以使用以下代码:

要将MultiColumnMode枚举绑定到组合框,例如:

cbMultiColumnMode.Properties.Items.AddRange(typeof(MultiColumnMode).GetEnumNames());

并获得选定的索引:

MultiColumnMode multiColMode = (MultiColumnMode)cbMultiColumnMode.SelectedIndex;

注意:在此示例中,我使用DevExpress组合框,您可以在Win Form Combobox中执行相同的操作


0

这次聚会有点晚了,

SelectedValue.ToString()方法应拉入DisplayedName。但是,本文的数据绑定枚举以及相关说明显示了一种便捷的方法,不仅可以实现此目的,而且可以向枚举添加自定义描述属性,并根据需要将其用作显示值。非常简单易行,所有内容大约有15行左右的代码(除非您计算花括号)。

这是非常漂亮的代码,您可以使其成为启动的扩展方法...


0

仅以这种方式使用强制转换:

if((YouEnum)ComboBoxControl.SelectedItem == YouEnum.Español)
{
   //TODO: type you code here
}

0

您可以使用扩展方法

 public static void EnumForComboBox(this ComboBox comboBox, Type enumType)
 {
     var memInfo = enumType.GetMembers().Where(a => a.MemberType == MemberTypes.Field).ToList();
     comboBox.Items.Clear();
     foreach (var member in memInfo)
     {
         var myAttributes = member.GetCustomAttribute(typeof(DescriptionAttribute), false);
         var description = (DescriptionAttribute)myAttributes;
         if (description != null)
         {
             if (!string.IsNullOrEmpty(description.Description))
             {
                 comboBox.Items.Add(description.Description);
                 comboBox.SelectedIndex = 0;
                 comboBox.DropDownStyle = ComboBoxStyle.DropDownList;
             }
         }   
     }
 }

如何使用...声明枚举

using System.ComponentModel;

public enum CalculationType
{
    [Desciption("LoaderGroup")]
    LoaderGroup,
    [Description("LadingValue")]
    LadingValue,
    [Description("PerBill")]
    PerBill
}

此方法在组合框项目中显示说明

combobox1.EnumForComboBox(typeof(CalculationType));

0

这为我工作:

comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
comboBox1.SelectedIndex = comboBox1.FindStringExact(MyEnum.something.ToString());
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.