【问题标题】:Binding an enum to a WinForms combo box, and then setting it将枚举绑定到 WinForms 组合框,然后设置它
【发布时间】:2010-10-28 18:13:13
【问题描述】:

很多人已经回答了如何将枚举绑定到 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

有人知道怎么做吗?

【问题讨论】:

  • 为什么不试试 ComboBox.SelectedValue 呢?
  • 如果你的问题已经得到解答,你真的应该选择一个答案。
  • 数据绑定枚举的点不是很清楚。枚举在运行时可能不会改变。您还可以编写一个扩展方法,用枚举的所有值填充组合框的项目集合。
  • @OliverFriedrich SelectedValue 给我带来了InvalidOperationException。 "不能在 ListControl 中设置 SelectedValue 和空的 ValueMember。"

标签: c# .net winforms combobox enums


【解决方案1】:

这对我有用:

comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
comboBox1.SelectedIndex = comboBox1.FindStringExact(MyEnum.something.ToString());

【讨论】:

  • 这个。最简单+最优雅的问题解决方案。只需确保您的 My.Settings。类型设置为枚举类型。
【解决方案2】:

这可能永远不会在所有其他响应中看到,但这是我想出的代码,这样做的好处是使用DescriptionAttribute(如果存在),否则使用枚举值的名称本身。

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

我得到具有FieldMemberType 并且是字面的成员。这将创建一个仅作为枚举值的成员的序列。这是稳健的,因为枚举不能有其他字段。

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";
    }


}

【讨论】:

  • 很实用的答案!谢谢!
【解决方案3】:

这些都不适合我,但确实如此(它还有一个额外的好处,就是能够更好地描述每个枚举的名称)。我不确定这是否是由于 .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;

【讨论】:

    【解决方案4】:

    你可以使用扩展方法

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

        为了简化:

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

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

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

        YourEnum enum = (YourEnum) yourComboBox.SelectedItem;
        

        如果要为组合框设置值:

        yourComboBox.SelectedItem = YourEnem.Foo;
        

        【讨论】:

        • 只要 Display 值与 Value 成员相同就可以使用,否则不行。
        • 如何绑定到实例?说枚举是一个类的成员? myCar.SpeedMode
        【解决方案7】:

        代码

        comboBox1.SelectedItem = MyEnum.Something;
        

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

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

        并检查它是否有效。

        【讨论】:

          【解决方案8】:

          假设你有以下枚举

          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并绑定到它。
          • 恕我直言,也许更完整的示例源代码,如果也有向 ComboBox 添加“All”/“Select All”选项等功能,用于过滤搜索中的所有行。
          【解决方案9】:

          根据@Amir Shenouda 的回答,我得到了这样的结论:

          枚举的定义:

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

          从中设置下拉值:

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

          从选中项中获取枚举:

          Status? status = cbStatus.SelectedValue as Status?;
          

          【讨论】:

          • 为什么要使用可空值?您可以使用显式强制转换(括号强制转换)而不使用可为空
          【解决方案10】:

          这个聚会有点晚了,

          SelectedValue.ToString() 方法应该引入 DisplayedName 。 然而,这篇文章DataBinding Enum and also With Descriptions 展示了一种方便的方法,不仅可以拥有它,而且您可以向枚举添加自定义描述属性,如果您愿意,可以将其用作显示的值。非常简单易行,大约 15 行左右的代码(除非你算上花括号)。

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

          【讨论】:

            【解决方案11】:

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

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

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

            并获得选定的索引:

            MultiColumnMode multiColMode = (MultiColumnMode)cbMultiColumnMode.SelectedIndex;
            

            注意:我在这个例子中使用了 DevExpress 组合框,你可以在 Win Form Combobox 中做同样的事情

            【讨论】:

              【解决方案12】:
                  public enum Colors
                  {
                      Red = 10,
                      Blue = 20,
                      Green = 30,
                      Yellow = 40,
                  }
              
              comboBox1.DataSource = Enum.GetValues(typeof(Colors));
              

              完整源码...Binding an enum to Combobox

              【讨论】:

                【解决方案13】:
                 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;
                    }
                

                【讨论】:

                • 你是什么意思?我不明白你的评论。此扩展方法有效
                • 这取决于您的枚举数是否允许 OR 标志。如果是这样,您可以添加一个名为 All 的 255 标志,并使用 All 作为 enum1 调用该函数,这将创建默认值。即comboBox1.FillByEnumOrderByName(MyEnum.All)
                • 这样的任何选项:var l = values.OrderBy(x=>x.Value).ToList(); l.Insert(0, "All");
                • 我的枚举是枚举 A { 鸭 = 0, 天鹅 = 1, 小丑 = 3};你的系统不适用于我的情况。
                【解决方案14】:

                试试这个:

                // fill list
                MyEnumDropDownList.DataSource = Enum.GetValues(typeof(MyEnum));
                
                // binding
                MyEnumDropDownList.DataBindings.Add(new Binding("SelectedValue", StoreObject, "StoreObjectMyEnumField"));
                

                StoreObject 是我的对象示例,其中 StoreObjectMyEnumField 属性用于存储 MyEnum 值。

                【讨论】:

                • 这是迄今为止最好的方法,但它对我不起作用。我不得不使用“SelectedItem”而不是“SelectedValue”
                【解决方案15】:

                这一直是个问题。 如果你有一个排序枚举,比如从 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
                

                【讨论】:

                  【解决方案16】:

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

                  显示将是名称。 选定的值将是 Enum 本身

                  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;
                      }
                  

                  【讨论】:

                    【解决方案17】:

                    将枚举转换为字符串列表并将其添加到组合框

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

                    使用 selectedItem 设置显示的值

                    comboBox1.SelectedItem = SomeEnum.SomeValue;
                    

                    【讨论】:

                      【解决方案18】:

                      枚举

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

                      从中设置下拉值

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

                      从所选项目中获取枚举

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

                      【讨论】:

                      • 这正是OP不想使用的方式。问题是用户在每个值的代码中显示名称,这需要重构并且大多数时候对用户不友好。
                      • 这可以在 C# 4.5 及更高版本中进一步简化为:Enum.TryParse(cbStatus.SelectedValue.ToString(), out status);
                      【解决方案19】:

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

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

                      然后使用枚举项作为文本:

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

                      【讨论】:

                        【解决方案20】:
                        comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
                        
                        comboBox1.SelectedIndex = (int)MyEnum.Something;
                        
                        comboBox1.SelectedIndex = Convert.ToInt32(MyEnum.Something);
                        

                        这两个都对我有用,你确定没有其他问题吗?

                        【讨论】:

                        • 不确定如果使用自定义枚举值(即enum MyEnum { Something = 47 }
                        【解决方案21】:

                        这里可能是老问题,但我遇到了问题,解决方案很简单,我找到了这个http://www.c-sharpcorner.com/UploadFile/mahesh/1220/

                        它利用了数据绑定并且运行良好,因此请检查一下。

                        【讨论】:

                          【解决方案22】:
                          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 添加“All”/“Select All”选项等功能,用于过滤搜索中的所有行。
                          【解决方案23】:

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

                              ''' <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
                          

                          【讨论】:

                            【解决方案24】:

                            目前我使用的是 Items 属性而不是 DataSource,这意味着我必须为每个枚举值调用 Add,但它是一个小枚举,并且无论如何都是它的临时代码。

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

                            临时解决方案,但现在是 YAGNI。

                            为这些想法喝彩,我可能会在获得一轮客户反馈后做正确的版本时使用它们。

                            【讨论】:

                              【解决方案25】:

                              您可以使用 KeyValuePair 值列表作为组合框的数据源。您将需要一个帮助方法,您可以在其中指定枚举类型并返回 IEnumerable> 其中 int 是枚举的值,字符串是枚举值的名称。在您的组合框中,将 DisplayMember 属性设置为“Key”,将 ValueMember 属性设置为“Value”。 Value 和 Key 是 KeyValuePair 结构的公共属性。然后,当您将 SelectedItem 属性设置为您正在做的枚举值时,它应该可以工作。

                              【讨论】:

                                【解决方案26】:

                                您可以使用“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
                                

                                【讨论】:

                                  【解决方案27】:
                                  comboBox1.SelectedItem = MyEnum.Something;
                                  

                                  应该可以正常工作......你怎么知道SelectedItem 是空的?

                                  【讨论】:

                                  • 我可以在调试器中查看。我认为这是因为 SelectedItem 的类型是对象,即引用类型,而枚举是值类型。虽然我希望编译器能够捕捉到这一点。
                                  【解决方案28】:

                                  试试:

                                  comboBox1.SelectedItem = MyEnum.Something;
                                  

                                  编辑:

                                  哎呀,你已经尝试过了。但是,当我的组合框设置为 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;` 非常棒,但是如果您希望组合框中的内容是字符串,例如组合框中的一项是“可咀嚼的维生素丸”。?
                                  猜你喜欢
                                  • 2012-08-19
                                  • 1970-01-01
                                  • 2011-08-04
                                  • 2018-11-12
                                  • 2020-02-07
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 2016-02-06
                                  • 1970-01-01
                                  相关资源
                                  最近更新 更多