Associare un'enumerazione a una casella combinata WinForms e quindi impostarla


122

molte persone hanno risposto alla domanda su come associare un enum a una casella combinata in WinForms. È così:

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

Ma questo è abbastanza inutile senza essere in grado di impostare il valore effettivo da visualizzare.

Ho provato:

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

Ho anche provato:

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

Qualcuno ha qualche idea su come farlo?


2
Perché non provare invece il ComboBox.SelectedValue?
Oliver Friedrich

5
Se la tua domanda ha avuto una risposta, dovresti davvero scegliere una risposta.
Ryan The Leach

Il punto di associazione di dati a un'enumerazione non è del tutto chiaro. È probabile che un'enumerazione non cambierà durante il runtime. Puoi anche scrivere un metodo di estensione che riempia la raccolta di elementi della casella combinata con tutti i valori dell'enumerazione.
Andreas


@OliverFriedrich SelectedValuecausa un InvalidOperationExceptionper me. "Impossibile impostare il SelectedValuein un ListControlcon un vuoto ValueMember."
Tyler

Risposte:


161

L'Enum

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

Impostazione dei valori a discesa da esso

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

Ottenere l'enumerazione dall'elemento selezionato

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

5
Grazie, per me funziona. Tieni presente che il tryparse è un'istruzione .net 4.0.
real_yggdrasil

Per me SelectedValue è sempre nullo. Sembra che la casella combinata non venga inizializzata. (MyEnum) this.GridView.CurrentRow.Cells [ "comboColumnCell"]. Valore. Riesco a vedere il valore ma internamente genera un'eccezione del puntatore nullo
ssal

3
Questo è esattamente il modo in cui l'OP non vuole usare. Il problema è che all'utente viene visualizzato il nome nel codice di ogni valore, che è soggetto a refactoring e non facile da usare la maggior parte delle volte.
Alejandro

5
Perché utilizzare TryParse anziché Parse? ... var status (Status) Enum.Parse (typeof (Status), cbStatus.SelectedValue.ToString ()); ... Hai associato l'enumerazione alla casella combinata in modo da SAPERE che il valore deve essere un valore enum valido e se non è allora che qualcosa sia andato storto e probabilmente vuoi un'eccezione.
bytedev

1
Perché questo è votato all'oblio? La domanda è come impostare programmaticamente il valore selezionato della casella combinata, utilizzando uno dei valori di enum.
Tyler

39

Per semplificare:

Prima inizializza questo comando: (ad es. Dopo InitalizeComponent())

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

Per recuperare l'elemento selezionato nella casella combinata:

YourEnum enum = (YourEnum) yourComboBox.SelectedItem;

Se vuoi impostare un valore per la casella combinata:

yourComboBox.SelectedItem = YourEnem.Foo;

2
Questo funziona fintanto che il valore di visualizzazione è lo stesso del membro Value, altrimenti no.
Lord of Scripts

15

Il codice

comboBox1.SelectedItem = MyEnum.Something;

va bene, il problema deve risiedere nel DataBinding. Le assegnazioni di DataBinding avvengono dopo il costruttore, principalmente la prima volta che viene visualizzata la casella combinata. Prova a impostare il valore nell'evento Load. Ad esempio, aggiungi questo codice:

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

E controlla se funziona.


12

Provare:

comboBox1.SelectedItem = MyEnum.Something;

Modifiche:

Ops, l'hai già provato. Tuttavia, ha funzionato per me quando il mio comboBox era impostato per essere un DropDownList.

Ecco il mio codice completo che funziona per me (sia con DropDown che 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, è fantastico che tu possa fare `comboBox1.SelectedItem = BlahEnum.Blue;` ma cosa succede se vuoi che le cose nella casella combinata siano stringhe, ad esempio un elemento della casella combinata come "pillola vitaminica masticabile"?
barlop

11

Diciamo che hai la seguente enumerazione

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

È necessario disporre di una struttura per mappare quei valori su una stringa:

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

Ora restituisci un array di oggetti con tutte le enumerazioni mappate su una stringa:

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 usa quanto segue per popolare la tua casella combinata:

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

Crea una funzione per recuperare il tipo enum nel caso in cui desideri passarlo a una funzione

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

e allora dovresti stare bene :)


+1 bella soluzione. Recentemente ha avuto questo problema e risolto in modo simile (solo con un Tupleinvece). Trasformerei sia il valore enum che la descrizione in proprietà, quindi aggiungerei un numberCB.DisplayProperty = "Caption"; `e in numberCB.ValueProperty = "Num"modo che tu possa usarlo SelectedValuedirettamente e associarlo.
Alejandro

IMHO, forse codice sorgente di esempio più completo, se c'è anche funzionalità come Aggiungi "Tutto" / "Seleziona tutto" opzione a ComboBox utilizzata per filtrare tutte le righe in una ricerca.
Kiquenet

5

Prova questo:

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

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

StoreObject è il mio esempio di oggetto con la proprietà StoreObjectMyEnumField per il valore del negozio MyEnum.


1
Questo è di gran lunga l'approccio migliore, ma così com'è, non ha funzionato per me. Ho dovuto usare "SelectedItem" invece di "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;
    }

cosa intendi ? Non ho capito il tuo commento. questo metodo di estensione funziona
Mickey Perlstein

Ciò dipende dal fatto che i tuoi numeri enum consentano OR FLags. in tal caso è possibile aggiungere un flag 255 chiamato All e chiamare la funzione con All come enum1, che crea l'impostazione predefinita. cioè comboBox1.FillByEnumOrderByName (MyEnum.All)
Mickey Perlstein

Qualsiasi opzione come questa: var l = values.OrderBy (x => x.Value) .ToList (); l.Insert (0, "All");
Kiquenet

la mia enumerazione è enum A {duck = 0, swan = 1, joker = 3}; il tuo sistema non funzionerà per la mia situazione.
Mickey Perlstein,

3

questa è la soluzione per caricare item of enum in combobox:

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

Quindi usa l'elemento enum come testo:

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

3

Sulla base della risposta di @Amir Shenouda, finisco con questo:

Definizione di Enum:

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

Impostazione dei valori a discesa da esso:

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

Ottenere l'enumerazione dall'elemento selezionato:

Status? status = cbStatus.SelectedValue as Status?;

2
perché usare nullable? È possibile utilizzare il casting esplicito (casting tra parentesi) e non usare 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
}

IMHO, forse codice sorgente di esempio più completo, se c'è anche funzionalità come Aggiungi "Tutto" / "Seleziona tutto" opzione a ComboBox utilizzata per filtrare tutte le righe in una ricerca.
Kiquenet


1

Uso il seguente metodo di supporto, che puoi associare alla tua 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

Converti l'enumerazione in un elenco di stringhe e aggiungilo al comboBox

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

Impostare il valore visualizzato utilizzando selectedItem

comboBox1.SelectedItem = SomeEnum.SomeValue;

1

Nessuno di questi ha funzionato per me, ma questo ha funzionato (e ha avuto l'ulteriore vantaggio di poter avere una descrizione migliore per il nome di ogni enum). Non sono sicuro se sia dovuto agli aggiornamenti di .net o meno, ma a prescindere penso che questo sia il modo migliore. Dovrai aggiungere un riferimento 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";
    }

Quindi quando vuoi accedere ai dati usa queste due righe:

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

1

Questo probabilmente non verrà mai visto tra tutte le altre risposte, ma questo è il codice che mi è venuto in mente, questo ha il vantaggio di usare il DescriptionAttributese esiste, ma altrimenti usando il nome del valore enum stesso.

Ho usato un dizionario perché ha un modello di elemento chiave / valore già pronto. Anche A List<KeyValuePair<string,object>>funzionerebbe e senza l'hashing non necessario, ma un dizionario rende il codice più pulito.

Ottengo membri che hanno un MemberTypedi Fielde che sono letterali. Questo crea una sequenza di soli membri che sono valori enum. Questo è robusto poiché un'enumerazione non può avere altri campi.

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;

dovrebbe funzionare bene ... Come fai a sapere che SelectedItemè nullo?


Posso controllarlo nel debugger. Presumo sia perché il tipo di SelectedItem è object, cioè un tipo di riferimento, e le enumerazioni sono tipi di valore. Anche se mi sarei aspettato che il compilatore lo prendesse.

0

È possibile utilizzare le funzioni "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

È possibile utilizzare un elenco di valori KeyValuePair come origine dati per la casella combinata. Avrai bisogno di un metodo di supporto in cui puoi specificare il tipo di enum e restituisce IEnumerable> dove int è il valore di enum e string è il nome del valore di enum. Nella tua casella combinata, imposta la proprietà DisplayMember su "Key" e la proprietà ValueMember su "Value". Value e Key sono proprietà pubbliche della struttura KeyValuePair. Quindi, quando imposti la proprietà SelectedItem su un valore enum come stai facendo, dovrebbe funzionare.


0

Al momento sto usando la proprietà Items piuttosto che DataSource, significa che devo chiamare Add per ogni valore enum, ma è un enum piccolo e comunque il suo codice temporaneo.

Quindi posso semplicemente fare il Convert.ToInt32 sul valore e impostarlo con SelectedIndex.

Soluzione temporanea, ma YAGNI per ora.

Grazie per le idee, probabilmente le userò quando realizzerò la versione corretta dopo aver ricevuto un giro di feedback dai clienti.



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

comboBox1.SelectedIndex = (int)MyEnum.Something;

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

Entrambi funzionano per me, sei sicuro che non ci sia qualcos'altro che non va?


2
Non sono sicuro che funzionerebbe se si utilizzassero valori enum personalizzati, ad esempioenum MyEnum { Something = 47 }
Samantha Branham,

0

Metodo generico per impostare un'enumerazione come origine dati per gli elenchi a discesa

Il display sarebbe il nome. Il valore selezionato sarebbe Enum stesso

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

È sempre stato un problema. se hai un ordinamento enumerativo, come da 0 a ...

public enum Test
      one
      Two
      Three
 End

puoi associare i nomi alla casella combinata e invece di usare l' .SelectedValueuso delle proprietà.SelectedIndex

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

e il

Dim x as byte = 0
Combobox.Selectedindex=x

0

In Framework 4 è possibile utilizzare il codice seguente:

Ad esempio, per associare l'enumerazione MultiColumnMode alla casella combinata:

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

e per ottenere l'indice selezionato:

MultiColumnMode multiColMode = (MultiColumnMode)cbMultiColumnMode.SelectedIndex;

nota: utilizzo DevExpress combobox in questo esempio, puoi fare lo stesso in Win Form Combobox


0

Un po 'tardi per questa festa,

Il metodo SelectedValue.ToString () dovrebbe inserire DisplayedName. Tuttavia, questo articolo DataBinding Enum e anche With Descriptions mostra un modo pratico non solo per averlo, ma puoi invece aggiungere un attributo di descrizione personalizzato all'enumerazione e utilizzarlo per il valore visualizzato se preferisci. Molto semplice e facile e circa 15 righe di codice (a meno che non contate le parentesi graffe) per tutto.

È un codice piuttosto ingegnoso e puoi renderlo un metodo di estensione per l'avvio ...


0

usa solo il casting in questo modo:

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

0

Puoi usare un metodo di estensione

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

Come usare ... Dichiara enum

using System.ComponentModel;

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

Questo metodo mostra la descrizione negli elementi della casella combinata

combobox1.EnumForComboBox(typeof(CalculationType));

0

Questo ha funzionato per me:

comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
comboBox1.SelectedIndex = comboBox1.FindStringExact(MyEnum.something.ToString());
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.