Enlazar una enumeración a un cuadro combinado de WinForms y luego configurarlo


122

Mucha gente ha respondido a la pregunta de cómo vincular una enumeración a un cuadro combinado en WinForms. Es como esto:

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

Pero eso es bastante inútil sin poder establecer el valor real para mostrar.

Yo he tratado:

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

También he intentado:

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

¿Alguien tiene alguna idea de cómo hacer esto?


2
¿Por qué no probar el ComboBox.SelectedValue en su lugar?
Oliver Friedrich

55
Si su pregunta ha sido respondida, realmente debería elegir una respuesta.
Ryan The Leach

El punto de vinculación de datos de una enumeración no está del todo claro. Es probable que una enumeración no cambie durante el tiempo de ejecución. También puede escribir un método de extensión que llene la colección de elementos del cuadro combinado con todos los valores de la enumeración.
Andreas


@OliverFriedrich me SelectedValuecausa una InvalidOperationException. "No se puede establecer el SelectedValueen un ListControlcon un vacío ValueMember".
Tyler

Respuestas:


161

La enumeración

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

Establecer los valores desplegables de él

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

Obtener la enumeración del elemento seleccionado

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

55
Gracias, esto funciona para mi. Tenga en cuenta que el tryparse es una declaración .net 4.0.
real_yggdrasil

Para mí SelectedValue siempre es nulo. Parece que el cuadro combinado no se inicializa. (myEnum) this.GridView.CurrentRow.Cells ["comboColumnCell"]. Valor. Puedo ver el valor, pero internamente arroja una excepción de puntero nulo
sal

3
Esta es precisamente la forma en que el OP no quiere usar. El problema es que el usuario muestra el nombre en código de cada valor, que está sujeto a refactorización y no es fácil de usar la mayoría de las veces.
Alejandro

55
¿Por qué usar TryParse en lugar de Parse? ... var status (Estado) Enum.Parse (typeof (Estado), cbStatus.SelectedValue.ToString ()); ... Vincula la enumeración al cuadro combinado para que SABES que el valor debe ser un valor de enumeración válido y si no es que algo haya salido muy mal y probablemente quieras una excepción.
bytedev

1
¿Por qué está esto votado al olvido? La pregunta es cómo establecer mediante programación el valor seleccionado del cuadro combinado, utilizando uno de los valores de la enumeración.
Tyler

39

Simplificar:

Primero inicialice este comando: (por ejemplo, después InitalizeComponent())

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

Para recuperar el elemento seleccionado en el cuadro combinado:

YourEnum enum = (YourEnum) yourComboBox.SelectedItem;

Si desea establecer el valor para el cuadro combinado:

yourComboBox.SelectedItem = YourEnem.Foo;

2
Esto funciona siempre que el valor de visualización sea el mismo que el miembro de valor, de lo contrario no.
Lord of Scripts

15

El código

comboBox1.SelectedItem = MyEnum.Something;

está bien, el problema debe residir en el enlace de datos. Las asignaciones de DataBinding ocurren después del constructor, principalmente la primera vez que se muestra el cuadro combinado. Intente establecer el valor en el evento Load. Por ejemplo, agregue este código:

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

Y verifica si funciona.


12

Tratar:

comboBox1.SelectedItem = MyEnum.Something;

EDICIONES:

Vaya, ya lo has intentado. Sin embargo, funcionó para mí cuando mi comboBox se configuró como DropDownList.

Aquí está mi código completo que funciona para mí (con DropDown y 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;
    }
}

interesante, es genial que pueda hacer `comboBox1.SelectedItem = BlahEnum.Blue;` pero ¿qué pasa si desea que las cosas en el cuadro combinado sean cadenas, por ejemplo, un elemento del cuadro combinado para ser "píldora de vitamina masticable"?
barlop

11

Digamos que tienes la siguiente enumeración

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

Debe tener una estructura para asignar esos valores a una cadena:

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

Ahora devuelva una matriz de objetos con todas las enumeraciones asignadas a una cadena:

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

Y use lo siguiente para completar su cuadro combinado:

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

Cree una función para recuperar el tipo de enumeración en caso de que desee pasarlo a una función

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

y entonces deberías estar bien :)


+1 buena solución. Recientemente tuve este mismo problema y lo resolví de manera similar (solo con un Tupleen su lugar). Convertiría tanto el valor de enumeración como la descripción en propiedades, luego agregaría a numberCB.DisplayProperty = "Caption"; `y numberCB.ValueProperty = "Num"para que pueda usarlo SelectedValuedirectamente y vincularlo.
Alejandro

En mi humilde opinión, tal vez el código fuente de muestra más completo, si también hay funcionalidad como Agregar "Todos" / "Seleccionar todo" opción a ComboBox utilizado para filtrar todas las filas en una búsqueda.
Kiquenet

5

Prueba esto:

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

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

StoreObject es mi ejemplo de objeto con la propiedad StoreObjectMyEnumField para almacenar el valor MyEnum.


1
Este es el mejor enfoque con diferencia, pero tal como es, no funcionó para mí. Tuve que usar "SelectedItem" en lugar de "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;
    }

Qué quieres decir ? No entendí tu comentario. este método de extensión funciona
Mickey Perlstein

Eso depende de si sus números de enumeración permiten OR FLags. si es así, puede agregar un indicador que sea 255 llamado All y llamar a la función con All como enum1, lo que crea el valor predeterminado. es decir, comboBox1.FillByEnumOrderByName (MyEnum.All)
Mickey Perlstein

Cualquier opción como esta: var l = values.OrderBy (x => x.Value) .ToList (); l.Insertar (0, "Todos");
Kiquenet

mi enumeración es enumeración A {pato = 0, cisne = 1, comodín = 3}; Su sistema no funcionará para mi situación.
Mickey Perlstein

3

Esta es la solución para cargar el elemento de enumeración en el cuadro combinado:

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

Y luego use el elemento enum como texto:

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

3

Basado en la respuesta de @Amir Shenouda termino con esto:

Definición de Enum:

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

Establecer los valores desplegables a partir de él:

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

Obtener la enumeración del elemento seleccionado:

Status? status = cbStatus.SelectedValue as Status?;

2
¿Por qué usar nullable? Podrías usar un casting explícito (paréntesis) y no usar nullable
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
}

En mi humilde opinión, tal vez el código fuente de muestra más completo, si también hay funcionalidad como Agregar "Todos" / "Seleccionar todo" opción a ComboBox utilizado para filtrar todas las filas en una búsqueda.
Kiquenet


1

Utilizo el siguiente método auxiliar, que puedes vincular a tu lista.

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

Convierta la enumeración en una lista de cadenas y agréguela al cuadro combinado

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

Establezca el valor mostrado usando selectedItem

comboBox1.SelectedItem = SomeEnum.SomeValue;

1

Ninguno de estos funcionó para mí, pero esto funcionó (y tenía el beneficio adicional de poder tener una mejor descripción para el nombre de cada enumeración). No estoy seguro de si se debe a las actualizaciones de .net o no, pero creo que esta es la mejor manera. Deberá agregar una referencia a:

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

Luego, cuando desee acceder a los datos, use estas dos líneas:

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

1

Probablemente esto nunca se verá entre todas las otras respuestas, pero este es el código que se me ocurrió, tiene el beneficio de usar el DescriptionAttributesi existe, pero de lo contrario usar el nombre del valor enum.

Usé un diccionario porque tiene un patrón de elemento clave / valor listo. UNAList<KeyValuePair<string,object>> también funcionaría y sin el hashing innecesario, pero un diccionario crea un código más limpio.

Obtengo miembros que tienen un MemberTypede Fieldy que son literales. Esto crea una secuencia de solo miembros que son valores de enumeración. Esto es robusto ya que una enumeración no puede tener otros campos.

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;

debería funcionar bien ... ¿Cómo puedes saber que SelectedItemes nulo?


Puedo verificarlo en el depurador. Supongo que es porque el tipo de SelectedItem es objeto, es decir, un tipo de referencia, y las enumeraciones son tipos de valor. Aunque hubiera esperado que el compilador captara eso.

0

Puede usar las funciones "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

Puede usar una lista de valores KeyValuePair como fuente de datos para el cuadro combinado. Necesitará un método auxiliar donde puede especificar el tipo de enumeración y devuelve IEnumerable> donde int es el valor de enum y string es el nombre del valor de enumeración. En su cuadro combinado, establezca la propiedad DisplayMember en 'Key' y la propiedad ValueMember en 'Value'. Value y Key son propiedades públicas de la estructura KeyValuePair. Luego, cuando establece la propiedad SelectedItem en un valor de enumeración como lo está haciendo, debería funcionar.


0

En el momento en que estoy usando la propiedad Items en lugar de DataSource, significa que tengo que llamar a Add para cada valor de enumeración, pero es una enumeración pequeña y su código temporal de todos modos.

Entonces puedo hacer Convert.ToInt32 en el valor y configurarlo con SelectedIndex.

Solución temporal, pero YAGNI por ahora.

Felicidades por las ideas, probablemente las usaré cuando haga la versión adecuada después de recibir una ronda de comentarios de los clientes.



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

comboBox1.SelectedIndex = (int)MyEnum.Something;

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

Ambos de estos trabajos para mí ¿estás seguro de que no hay nada más malo?


2
No estoy seguro de que esto funcione si se utilizan valores de enumeración personalizados, es decir,enum MyEnum { Something = 47 }
Samantha Branham

0

Método genérico para establecer una enumeración como fuente de datos para menús desplegables

La pantalla sería el nombre. El valor seleccionado sería Enum mismo

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

Eso siempre fue un problema. si tiene una enumeración ordenada, como de 0 a ...

public enum Test
      one
      Two
      Three
 End

puede vincular nombres al cuadro combinado y en lugar de usar el .SelectedValueuso de propiedades.SelectedIndex

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

y el

Dim x as byte = 0
Combobox.Selectedindex=x

0

En Framework 4 puede usar el siguiente código:

Para vincular MultiColumnMode enum a combobox, por ejemplo:

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

y para obtener el índice seleccionado:

MultiColumnMode multiColMode = (MultiColumnMode)cbMultiColumnMode.SelectedIndex;

nota: utilizo el cuadro combinado DevExpress en este ejemplo, puede hacer lo mismo en el cuadro combinado Win Form


0

Un poco tarde para esta fiesta,

El método SelectedValue.ToString () debería extraer DisplayedName. Sin embargo, este artículo DataBinding Enum y también con descripciones muestra una manera práctica no solo de tener eso, sino que también puede agregar un atributo de descripción personalizado a la enumeración y usarlo para el valor mostrado si lo prefiere. Muy simple y fácil y aproximadamente 15 líneas de código (a menos que cuentes las llaves) para todo.

Es un código bastante ingenioso y puede convertirlo en un método de extensión para arrancar ...


0

solo usa el casting de esta manera:

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

0

Puedes usar un método de extensión

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

Cómo usar ... Declarar enumeración

using System.ComponentModel;

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

Este método muestra la descripción en los elementos del cuadro combinado

combobox1.EnumForComboBox(typeof(CalculationType));

0

Esto funcionó para mí:

comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
comboBox1.SelectedIndex = comboBox1.FindStringExact(MyEnum.something.ToString());
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.