Vincular uma enumeração a uma caixa de combinação WinForms e defini-la


122

muitas pessoas responderam à pergunta de como vincular uma enumeração a uma caixa de combinação no WinForms. É tipo isso:

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

Mas isso é bastante inútil sem poder definir o valor real a ser exibido.

Eu tentei:

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

Eu também tentei:

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

Alguém tem alguma idéia de como fazer isso?


2
Por que simplesmente não tentar o ComboBox.SelectedValue?
Oliver Friedrich

5
Se sua pergunta foi respondida, você realmente deve escolher uma resposta.
Ryan The Leach

O ponto de vincular um enum não é muito claro. Um enum provavelmente não será alterado durante o tempo de execução. Você também pode escrever um método de extensão que preencha a coleção de itens da caixa de combinação com todos os valores da enumeração.
555 Andreas


@OliverFriedrich SelectedValuecausa um problema InvalidOperationExceptionpara mim. "Não é possível definir o SelectedValueem a ListControlcom um vazio ValueMember."
Tyler #

Respostas:


161

The Enum

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

Definindo os valores suspensos a partir dele

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

Obtendo a enumeração do item selecionado

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

5
Obrigado, isso funciona para mim. Tenha em mente que o tryparse é uma instrução .net 4.0.
real_yggdrasil 22/06

Para mim SelectedValue é sempre nulo. Parece que a caixa de combinação não é inicializada. (myEnum) this.GridView.CurrentRow.Cells ["comboColumnCell"]. Value. Eu posso ver o valor, mas internamente ele lança exceção de ponteiro nulo
ssal

3
É exatamente dessa maneira que o OP não deseja usar. O problema é que o usuário exibe o nome no código de cada valor, que está sujeito a refatoração e não é amigável na maioria das vezes.
Alejandro

5
Por que usar o TryParse em vez do Parse? ... var status (Status) Enum.Parse (typeof (Status), cbStatus.SelectedValue.ToString ()); ... Você vincula a enumeração à caixa de combinação para SABER que o valor deve ser um valor de enumeração válido e se não é, então algo deu muito errado e você provavelmente deseja uma exceção.
Bydevev

1
Por que isso é votado para o esquecimento? A questão é como definir programaticamente o valor selecionado da caixa de combinação, usando um dos valores da enumeração.
Tyler

39

Para simplificar:

Primeiro inicialize este comando: (por exemplo, depois InitalizeComponent())

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

Para recuperar o item selecionado na caixa de combinação:

YourEnum enum = (YourEnum) yourComboBox.SelectedItem;

Se você deseja definir um valor para a caixa de combinação:

yourComboBox.SelectedItem = YourEnem.Foo;

2
Isso funciona desde que o valor de exibição seja o mesmo que o membro de valor, caso contrário, não.
Lord of Scripts

15

O código

comboBox1.SelectedItem = MyEnum.Something;

está ok, o problema deve residir no DataBinding. As atribuições de ligação de dados ocorrem após o construtor, principalmente na primeira vez em que a caixa de combinação é exibida. Tente definir o valor no evento Load. Por exemplo, adicione este código:

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

E verifique se funciona.


12

Experimentar:

comboBox1.SelectedItem = MyEnum.Something;

EDITAR% S:

Opa, você já tentou isso. No entanto, funcionou para mim quando meu comboBox foi definido como DropDownList.

Aqui está o meu código completo que funciona para mim (com o DropDown e o 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;
    }
}

interessante, é ótimo que você possa fazer `comboBox1.SelectedItem = BlahEnum.Blue;` mas e se você quiser que as coisas na caixa de combinação sejam seqüências de caracteres, por exemplo, um item da caixa de combinação seja "pílula de vitamina para mastigar".?
barlop

11

Digamos que você tenha a seguinte enumeração

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

Você precisa ter uma estrutura para mapear esses valores para uma sequência:

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

Agora retorne uma matriz de objetos com todas as enumerações mapeadas para uma string:

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

E use o seguinte para preencher sua caixa de combinação:

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

Crie uma função para recuperar o tipo de enumeração, caso você queira passá-la para uma função

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

e então você deve ficar bem :)


Uma boa solução. Recentemente tive esse mesmo problema e resolvi de maneira semelhante (apenas com um Tuple). Eu transformaria o valor do enum e a descrição em propriedades e, em seguida, adicionaria a numberCB.DisplayProperty = "Caption"; `e numberCB.ValueProperty = "Num"para que você possa usar SelectedValuediretamente e vincular a ele.
Alejandro

IMHO, talvez um código-fonte de amostra mais completo, se também houver uma funcionalidade como a opção Adicionar "Todos" / "Selecionar tudo" ao ComboBox, usada para filtrar todas as linhas de uma pesquisa.
Kiquenet 17/10

5

Tente o seguinte:

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

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

StoreObject é meu exemplo de objeto com a propriedade StoreObjectMyEnumField para o valor da loja MyEnum.


1
Essa é a melhor abordagem, de longe, mas, como ela é, não funcionou para mim. Eu tive que usar "SelectedItem" em vez 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;
    }

O que você quer dizer ? Não entendi o seu comentário. este método de extensão funciona
Mickey Perlstein 21/10

Isso depende se o seu número de enumeração permitir OR FLags. se assim for, você pode adicionar um sinalizador 255 chamado All e chamar a função com All como enum1, que cria o padrão. ou seja, comboBox1.FillByEnumOrderByName (MyEnum.All)
Mickey Perlstein

Qualquer opção como esta: var l = values.OrderBy (x => x.Value) .ToList (); l.Inserir (0, "Todos");
Kiquenet 22/10/2014

meu enum é enum A {duck = 0, cisne = 1, coringa = 3}; seu sistema não funcionará para a minha situação.
quer

3

esta é a solução para carregar o item de enum na caixa de combinação:

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

E, em seguida, use o item enum como texto:

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

3

Com base na resposta de @Amir Shenouda, termino com isso:

Definição de Enum:

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

Definindo os valores suspensos a partir dele:

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

Obtendo a enumeração do item selecionado:

Status? status = cbStatus.SelectedValue as Status?;

2
por que usar anulável? Você pode usar conversão explícita (fundição parênteses) e não usar anulável
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
}

IMHO, talvez um código-fonte de amostra mais completo, se também houver uma funcionalidade como a opção Adicionar "Todos" / "Selecionar tudo" ao ComboBox, usada para filtrar todas as linhas de uma pesquisa.
Kiquenet


1

Eu uso o seguinte método auxiliar, que você pode vincular à sua 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

Converta o enum em uma lista de strings e adicione-o ao comboBox

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

Defina o valor exibido usando selectedItem

comboBox1.SelectedItem = SomeEnum.SomeValue;

1

Nenhuma delas funcionou para mim, mas funcionou (e teve o benefício adicional de poder ter uma descrição melhor para o nome de cada enumeração). Não tenho certeza se é devido a atualizações .net ou não, mas, independentemente disso, acho que essa é a melhor maneira. Você precisará adicionar uma referência a:

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

Então, quando você quiser acessar os dados, use estas duas linhas:

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

1

Isso provavelmente nunca será visto entre todas as outras respostas, mas esse é o código que eu criei, isso tem o benefício de usar o método DescriptionAttribute se ele existir, mas de outro modo o nome do próprio valor da enumeração.

Eu usei um dicionário porque ele tem um padrão de item de chave / valor pronto. UMAList<KeyValuePair<string,object>> também funcionaria e sem o hash desnecessário, mas um dicionário contribui para um código mais limpo.

Recebo membros que têm um MemberTypedos Fielde que são literal. Isso cria uma sequência de apenas membros que são valores de enumeração. Isso é robusto, pois uma enumeração não pode ter outros 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;

deve funcionar muito bem ... Como você pode dizer que SelectedItemé nulo?


Eu posso verificá-lo no depurador. Suponho que é porque o tipo de SelectedItem é objeto, ou seja, um tipo de referência e enumerações são tipos de valor. Embora eu esperasse que o compilador entendesse isso.

0

Você pode usar as funções "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

Você pode usar uma lista de valores KeyValuePair como fonte de dados para a caixa de combinação. Você precisará de um método auxiliar em que possa especificar o tipo de enum e ele retornará IEnumerable> em que int é o valor de enum e string é o nome do valor de enum. Na sua caixa de combinação, defina a propriedade DisplayMember como 'Key' e a propriedade ValueMember como 'Value'. Valor e Chave são propriedades públicas da estrutura KeyValuePair. Em seguida, quando você define a propriedade SelectedItem como um valor de enum, como você está fazendo, ela deve funcionar.


0

No momento, estou usando a propriedade Items em vez do DataSource, significa que tenho que chamar Add para cada valor de enumeração, mas é uma enumeração pequena e seu código temporário de qualquer maneira.

Então eu posso apenas fazer o Convert.ToInt32 no valor e defini-lo com SelectedIndex.

Solução temporária, mas YAGNI por enquanto.

Felicidades pelas idéias, provavelmente as usarei quando fizer a versão correta depois de receber uma rodada de comentários dos clientes.



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

comboBox1.SelectedIndex = (int)MyEnum.Something;

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

Ambos funcionam para mim. Tem certeza de que não há mais nada errado?


2
Não sei se este iria funcionar se usar valores enum personalizados, ou seja,enum MyEnum { Something = 47 }
Samantha Branham

0

Método genérico para definir uma enumeração como fonte de dados para menus suspensos

O display seria o nome. O valor selecionado seria o próprio 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;
    }

0

Isso sempre foi um problema. se você tiver um Enum classificado, como de 0 a ...

public enum Test
      one
      Two
      Three
 End

você pode vincular nomes à caixa de combinação e, em vez de usar o .SelectedValueuso da propriedade.SelectedIndex

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

e a

Dim x as byte = 0
Combobox.Selectedindex=x

0

No Framework 4, você pode usar o seguinte código:

Para ligar o MultiColumnMode enum à caixa de combinação, por exemplo:

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

e para obter o índice selecionado:

MultiColumnMode multiColMode = (MultiColumnMode)cbMultiColumnMode.SelectedIndex;

Nota: Eu uso a caixa de combinação DevExpress neste exemplo, você pode fazer o mesmo na caixa de combinação Win Form


0

Um pouco atrasado para esta festa,

O método SelectedValue.ToString () deve receber o DisplayedName. No entanto, este artigo DataBinding Enum e também With Descriptions mostra uma maneira útil de não apenas ter isso, mas, em vez disso, você pode adicionar um atributo de descrição personalizado à enum e usá-lo como valor exibido, se preferir. Muito simples e fácil e cerca de 15 linhas de código (a menos que você conte os chavetas) para tudo.

É um código bastante bacana e você pode torná-lo um método de extensão para inicializar ...


0

use somente a transmissão desta maneira:

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

0

Você pode usar um método de extensão

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

Como usar ... Declare enum

using System.ComponentModel;

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

Este método mostra a descrição nos itens da caixa de combinação

combobox1.EnumForComboBox(typeof(CalculationType));

0

Isso funcionou para mim:

comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
comboBox1.SelectedIndex = comboBox1.FindStringExact(MyEnum.something.ToString());
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.