Lier une énumération à une zone de liste déroulante WinForms, puis la définir


122

beaucoup de gens ont répondu à la question de savoir comment lier une énumération à une zone de liste déroulante dans WinForms. C'est comme ça:

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

Mais c'est assez inutile sans pouvoir définir la valeur réelle à afficher.

J'ai essayé:

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

J'ai également essayé:

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

Quelqu'un at-il des idées sur la façon de procéder?


2
Pourquoi ne pas essayer la ComboBox.SelectedValue à la place?
Oliver Friedrich

5
Si votre question a reçu une réponse, vous devriez vraiment choisir une réponse.
Ryan The Leach

Le but de la liaison de données à une énumération n'est pas tout à fait clair. Une énumération ne changera probablement pas pendant l'exécution. Vous pouvez également écrire une méthode d'extension qui remplirait la collection d'éléments de la zone de liste déroulante avec toutes les valeurs de l'énumération.
Andreas


@OliverFriedrich me SelectedValuecause un problème InvalidOperationException. "Impossible de définir le SelectedValuedans un ListControlavec un vide ValueMember."
Tyler

Réponses:


161

L'Enum

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

Définition des valeurs déroulantes à partir de celui-ci

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

Obtenir l'énumération de l'élément sélectionné

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

5
Merci, cela fonctionne pour moi. Gardez à l'esprit que le tryparse est une instruction .net 4.0.
real_yggdrasil

Pour moi, SelectedValue est toujours nul. Il semble que la combobox ne soit pas initialisée. (myEnum) this.GridView.CurrentRow.Cells ["comboColumnCell"]. Valeur. Je peux voir la valeur mais en interne, il jette une exception de pointeur nul
ssal

3
C'est précisément la façon dont l'OP ne veut pas utiliser. Le problème est que l'utilisateur affiche le nom dans le code de chaque valeur, qui est sujet à refactoring et pas convivial la plupart du temps.
Alejandro

5
Pourquoi utiliser TryParse plutôt que Parse? ... var status (Status) Enum.Parse (typeof (Status), cbStatus.SelectedValue.ToString ()); ... Vous avez lié l'énumération à la zone de liste déroulante pour savoir que la valeur doit être une valeur d'énumération valide et si ce n'est pas alors que quelque chose s'est très mal passé et vous voulez probablement une exception.
bytedev

1
Pourquoi est-ce voté pour l'oubli? La question est de savoir comment définir par programme la valeur sélectionnée de la zone de liste déroulante, en utilisant l'une des valeurs de l'énumération.
Tyler

39

Pour simplifier:

Initialisez d'abord cette commande: (par exemple après InitalizeComponent())

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

Pour récupérer l'élément sélectionné dans la liste déroulante:

YourEnum enum = (YourEnum) yourComboBox.SelectedItem;

Si vous souhaitez définir la valeur de la zone de liste déroulante:

yourComboBox.SelectedItem = YourEnem.Foo;

2
Cela fonctionne tant que la valeur d'affichage est la même que le membre Valeur, sinon pas.
Lord of Scripts

15

Le code

comboBox1.SelectedItem = MyEnum.Something;

est ok, le problème doit résider dans le DataBinding. Les affectations de DataBinding se produisent après le constructeur, principalement la première fois que la zone de liste déroulante est affichée. Essayez de définir la valeur dans l'événement Load. Par exemple, ajoutez ce code:

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

Et vérifiez si cela fonctionne.


12

Essayer:

comboBox1.SelectedItem = MyEnum.Something;

MODIFIER:

Oups, vous avez déjà essayé. Cependant, cela a fonctionné pour moi lorsque ma comboBox a été définie pour être une DropDownList.

Voici mon code complet qui fonctionne pour moi (avec DropDown et 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;
    }
}

intéressant, c'est génial que vous puissiez faire `comboBox1.SelectedItem = BlahEnum.Blue;` mais que faire si vous voulez que les éléments de la combobox soient des chaînes, par exemple un élément de la combobox soit une "pilule de vitamine à croquer".?
barlop

11

Disons que vous avez l'énumération suivante

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

Vous devez avoir une structure pour mapper ces valeurs à une chaîne:

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

Maintenant, retournez un tableau d'objets avec toutes les énumérations mappées sur une chaîne:

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

Et utilisez ce qui suit pour remplir votre zone de liste déroulante:

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

Créez une fonction pour récupérer le type enum juste au cas où vous voudriez le passer à une fonction

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

et alors tu devrais être ok :)


+1 belle solution. Récemment eu ce problème et résolu de la même manière (juste avec un à la Tupleplace). Je transformerais la valeur enum et la description en propriétés, puis ajouterais un numberCB.DisplayProperty = "Caption"; `et numberCB.ValueProperty = "Num"pour que vous puissiez l'utiliser SelectedValuedirectement et vous y lier.
Alejandro

À mon humble avis, peut-être un exemple de code source plus complet, s'il existe également des fonctionnalités telles que l'option Ajouter "Tout" / "Tout sélectionner" à ComboBox utilisée pour filtrer toutes les lignes d'une recherche.
Kiquenet

5

Essaye ça:

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

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

StoreObject est mon exemple d'objet avec la propriété StoreObjectMyEnumField pour la valeur de stockage MyEnum.


1
C'est de loin la meilleure approche, mais dans l'état actuel des choses, cela n'a pas fonctionné pour moi. J'ai dû utiliser "SelectedItem" au lieu 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;
    }

Que voulez-vous dire ? Je n'ai pas compris votre commentaire. cette méthode d'extension fonctionne
Mickey Perlstein

Cela dépend de si vos numéros d'énumération autorisent OU FLags. si tel est le cas, vous pouvez ajouter un indicateur qui est 255 appelé All et appeler la fonction avec All comme enum1, ce qui crée la valeur par défaut. ie comboBox1.FillByEnumOrderByName (MyEnum.All)
Mickey Perlstein

N'importe quelle option comme celle-ci: var l = values.OrderBy (x => x.Value) .ToList (); l.Insert (0, "Tous");
Kiquenet

mon énumération est enum A {canard = 0, cygne = 1, joker = 3}; votre système ne fonctionnera pas pour ma situation.
Mickey Perlstein

3

c'est la solution pour charger l'élément d'énumération dans combobox:

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

Et puis utilisez l'élément enum comme texte:

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

3

Sur la base de la réponse de @Amir Shenouda, je me retrouve avec ceci:

Définition d'énum:

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

Définition des valeurs déroulantes à partir de celui-ci:

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

Obtention de l'énumération à partir de l'élément sélectionné:

Status? status = cbStatus.SelectedValue as Status?;

2
pourquoi utiliser nullable? Vous pouvez utiliser un casting explicite (casting entre parenthèses) et ne pas utiliser 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
}

À mon humble avis, peut-être un exemple de code source plus complet, s'il existe également des fonctionnalités telles que l'option Ajouter "Tout" / "Tout sélectionner" à ComboBox utilisée pour filtrer toutes les lignes d'une recherche.
Kiquenet


1

J'utilise la méthode d'aide suivante, que vous pouvez lier à votre liste.

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

Convertissez l'énumération en une liste de chaînes et ajoutez-la à la comboBox

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

Définissez la valeur affichée à l'aide de selectedItem

comboBox1.SelectedItem = SomeEnum.SomeValue;

1

Aucun de ceux-ci n'a fonctionné pour moi, mais cela a fonctionné (et cela avait l'avantage supplémentaire de pouvoir avoir une meilleure description pour le nom de chaque énumération). Je ne sais pas si cela est dû à des mises à jour .net ou non, mais quoi qu'il en soit, je pense que c'est le meilleur moyen. Vous devrez ajouter une référence à:

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

Ensuite, lorsque vous souhaitez accéder aux données, utilisez ces deux lignes:

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

1

Cela ne sera probablement jamais vu parmi toutes les autres réponses, mais c'est le code que j'ai trouvé, cela a l'avantage d'utiliser le DescriptionAttributes'il existe, mais sinon d'utiliser le nom de la valeur enum elle-même.

J'ai utilisé un dictionnaire car il a un modèle d'élément clé / valeur prêt à l'emploi. A List<KeyValuePair<string,object>>fonctionnerait également et sans le hachage inutile, mais un dictionnaire rend le code plus propre.

Je reçois des membres qui ont un MemberTypede Fieldet qui sont littéraux. Cela crée une séquence de membres uniquement qui sont des valeurs d'énumération. Ceci est robuste car une énumération ne peut pas avoir d'autres champs.

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;

devrait fonctionner très bien ... Comment pouvez-vous dire que SelectedItemc'est nul?


Je peux le vérifier dans le débogueur. Je suppose que c'est parce que le type de SelectedItem est un objet, c'est-à-dire un type de référence, et les énumérations sont des types de valeur. Bien que j'aurais espéré que le compilateur attrape cela.

0

Vous pouvez utiliser les fonctions "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

Vous pouvez utiliser une liste de valeurs KeyValuePair comme source de données pour la zone de liste déroulante. Vous aurez besoin d'une méthode d'assistance où vous pouvez spécifier le type d'énumération et elle renvoie IEnumerable> où int est la valeur de enum et string est le nom de la valeur d'énumération. Dans votre liste déroulante, définissez la propriété DisplayMember sur «Key» et la propriété ValueMember sur «Value». Value et Key sont des propriétés publiques de la structure KeyValuePair. Ensuite, lorsque vous définissez la propriété SelectedItem sur une valeur enum comme vous le faites, cela devrait fonctionner.


0

Pour le moment, j'utilise la propriété Items plutôt que DataSource, cela signifie que je dois appeler Add pour chaque valeur d'énumération, mais c'est une petite énumération et son code temporaire quand même.

Ensuite, je peux simplement faire le Convert.ToInt32 sur la valeur et le définir avec SelectedIndex.

Solution temporaire, mais YAGNI pour l'instant.

Vive les idées, je les utiliserai probablement lorsque je créerai la bonne version après avoir reçu les commentaires des clients.



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

comboBox1.SelectedIndex = (int)MyEnum.Something;

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

Ces deux fonctionnent pour moi, êtes-vous sûr qu'il n'y a pas autre chose qui ne va pas?


2
Je ne suis pas sûr que cela fonctionne si vous utilisez des valeurs d'énumération personnalisées, c'est-à-direenum MyEnum { Something = 47 }
Samantha Branham

0

Méthode générique pour définir une énumération comme source de données pour les listes déroulantes

L'affichage serait le nom. La valeur sélectionnée serait Enum elle-même

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

Cela a toujours été un problème. si vous avez une énumération triée, comme de 0 à ...

public enum Test
      one
      Two
      Three
 End

vous pouvez lier les noms à la liste déroulante et au lieu d'utiliser la .SelectedValuepropriété, utilisez.SelectedIndex

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

et le

Dim x as byte = 0
Combobox.Selectedindex=x

0

Dans Framework 4, vous pouvez utiliser le code suivant:

Pour lier l'énumération MultiColumnMode à la zone de liste déroulante, par exemple:

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

et pour obtenir l'index sélectionné:

MultiColumnMode multiColMode = (MultiColumnMode)cbMultiColumnMode.SelectedIndex;

Remarque: j'utilise DevExpress combobox dans cet exemple, vous pouvez faire la même chose dans Win Form Combobox


0

Un peu en retard à cette fête,

La méthode SelectedValue.ToString () doit extraire le DisplayedName. Cependant, cet article DataBinding Enum et With Descriptions montre un moyen pratique non seulement d'avoir cela, mais à la place, vous pouvez ajouter un attribut de description personnalisé à l'énumération et l'utiliser pour votre valeur affichée si vous préférez. Très simple et facile et environ 15 lignes de code (sauf si vous comptez les accolades) pour tout.

C'est un code assez astucieux et vous pouvez en faire une méthode d'extension pour démarrer ...


0

utilisez uniquement la diffusion de cette façon:

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

0

Vous pouvez utiliser une méthode d'extension

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

Comment utiliser ... Declare enum

using System.ComponentModel;

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

Cette méthode affiche la description dans les éléments de la zone de liste déroulante

combobox1.EnumForComboBox(typeof(CalculationType));

0

Cela a fonctionné pour moi:

comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
comboBox1.SelectedIndex = comboBox1.FindStringExact(MyEnum.something.ToString());
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.