40

I would bind the values of an enumeration with a combobox control.

I've written this code:

cboPriorLogicalOperator.DataSource = Enum.GetValues(typeof(MyEnum))
    .Cast<MyEnum>()
    .Select(p => new { Key = (int)p, Value = p.ToString() })
    .ToList();

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

It works well but I wonder if there is a simpler way.

Homam
  • 23,263
  • 32
  • 111
  • 187
  • Why are you looking for a simpler solution if your solution works? – Security Hound Apr 12 '11 at 16:52
  • @ Ramhound: I though that maybe there is a *direct* way. I do understand my code but not every one can do that simply. So I looked for a simpler one. – Homam Apr 12 '11 at 16:54
  • 1
    @Homam I don't know if you intended it that way, but when I modeled after your code for my own solution I had to reverse the key and value types in my select statement in order to display the value in the combobox correctly. Your method ended up displaying the keys in the combobox. – gonzobrains Sep 06 '13 at 17:41
  • 2
    +1 for the question actually providing an answer! – gonzobrains Sep 06 '13 at 17:42

5 Answers5

24

I think your code is beautiful!

The only improvement would be to place the code in an Extension Method.

EDIT:

When I think about it, what you want to do is to use the Enum as in the definition and not an instance of the enum, which is required by extensions methods.

I found this question, which solves it really nicely:

public class SelectList
{
    // Normal SelectList properties/methods go here

    public static SelectList Of<T>()
    {
       Type t = typeof(T);
       if (t.IsEnum)
       {
           var values = from Enum e in Enum.GetValues(t)
                        select new { ID = e, Name = e.ToString() };
           return new SelectList(values, "Id", "Name");
       }
       return null;
    }
}

// called with 
var list = SelectList.Of<Things>();

Only you might want to return a Dictionary<int, string> and not a SelectList, but you get the idea.

EDIT2:

Here we go with a code example that covers the case you are looking at.

public class EnumList
{
    public static IEnumerable<KeyValuePair<T, string>> Of<T>()
    {
        return Enum.GetValues(typeof (T))
            .Cast<T>()
            .Select(p => new KeyValuePair<T, string>(p, p.ToString()))
            .ToList();
    }
}

Or this version perhaps, where the key is an int

public class EnumList
{
    public static IEnumerable<KeyValuePair<int, string>> Of<T>()
    {
        return Enum.GetValues(typeof (T))
            .Cast<T>()
            .Select(p => new KeyValuePair<int, string>(Convert.ToInt32(p), p.ToString()))
            .ToList();
    }
}
sairfan
  • 970
  • 2
  • 12
  • 20
Mikael Östberg
  • 16,982
  • 6
  • 61
  • 79
  • I agree. We have extended the winforms combo box into our own version, and have a BindToEnum method on it that works really well. It looks a lot like this code as well. – captncraig Apr 12 '11 at 16:39
  • Ah, they missed that in the original example. In your case it would return `Dictionary`, I think. – Mikael Östberg Apr 12 '11 at 17:30
  • I added some *real* code that you should be able to work with. I used an `IEnumerable>` because when I tested using the enum `HttpStatusCode` I got key duplicate problems and that made me choose this one over the `Dictionary – Mikael Östberg Apr 12 '11 at 18:02
6

Why not to use:

myComboBox.DataSource  = Enum.GetValues(typeof(MyEnum))

?

Jacob Seleznev
  • 8,013
  • 3
  • 24
  • 34
  • Because this doesn't bind key/value pairs. To get a value out of the combo box, you have to cast SelectedItem to the enum. See http://msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx, in the Remarks section. – Robert Harvey Jan 05 '12 at 20:32
  • I think if we want to set condition in retrieved data, the code in question is pretty good ...otherwise your code is better.. – Ali Jun 06 '17 at 17:15
1
foreach (int r in Enum.GetValues(typeof(MyEnum))) 
{
     var item = new ListItem(Enum.GetName(typeof(MyEnum), r), r.ToString());
     ddl.Items.Add(item);
}
hardba11
  • 1,478
  • 15
  • 27
0

I recently ran into a problem where I had a nullable enum property and needed to bind it to a ComboBox. Here is the solution I came up with:

using System;
using System.Collections.Generic;

namespace ActivitySchedule.Model
{
    public class NullableEnum<T> where T : struct, IComparable
    {
        public string Display { get; private set; }

        public T? Value { get; private set; }

        public static implicit operator T?(NullableEnum<T> o)
        {
            return o.Value;
        }

        public static implicit operator NullableEnum<T>(T? o)
        {
            return new NullableEnum<T>
            {
                Display = o?.ToString() ?? "NA",
                Value = o
            };
        }

        private NullableEnum() { }

        public static IEnumerable<NullableEnum<T>> GetList()
        {
            var items = new List<NullableEnum<T>>
            {
                new NullableEnum<T>
                {
                    Display = "NA",
                    Value = null
                }
            };

            var values = Enum.GetValues(typeof(T));

            foreach (T v in values)
            {
                items.Add(v);
            }

            return items;
        }
    }
}

I wrapped the object in a Controller class and change the property's Type like so:

private MyClass myClass;

public NullableEnum<MyEnum> MyEnum
{
    get { return this.myClass.MyEnum; }
    set { this.myClass.MyEnum = value.Value; }
}

(it could also be a derived class and override the property)

This is how I used it:

var types = NullableEnum<MyEnum>.GetList();
this.comboBox1.DataSource = types;
this.comboBox1.DisplayMember = "Display";
this.comboBox1.ValueMember = "Value";
this.comboBox1.Bindings.Add("SelectedValue", myClassController, "MyEnum");
-1
private void Form1_Load(object sender, EventArgs e)
{
    comboBox1.DataSource = Enum.GetValues( typeof(Gender));
    Array gen = Enum.GetValues(typeof(Gender));
    List<KeyValuePair<string, char>> lstgender = new List<KeyValuePair<string,char>>();
    foreach(Gender g in gen)
        lstgender.Add(new KeyValuePair<string,char>(g.ToString(),((char)g)));
    comboBox1.DataSource = lstgender;
    comboBox1.DisplayMember = "key";
    comboBox1.ValueMember = "value"
}

private void button1_Click(object sender, EventArgs e)
{
    MessageBox.Show(comboBox1.SelectedValue.ToString());
}

public class Student
{
    public string stud_name { get; set; }
    public Gender stud_gen { get; set; }
}

public enum Gender
{
    Male='M',
    Female='F'
}
Gerhard Powell
  • 5,965
  • 5
  • 48
  • 59