Powiązanie wyliczenia z polem kombi WinForms, a następnie ustawienie go


122

wiele osób odpowiedziało na pytanie, jak powiązać wyliczenie z polem kombi w WinForms. To jest tak:

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

Ale to jest całkiem bezużyteczne bez możliwości ustawienia rzeczywistej wartości do wyświetlenia.

Próbowałem:

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

Próbowałem też:

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

Czy ktoś ma jakieś pomysły jak to zrobić?


2
Dlaczego po prostu nie spróbować zamiast tego ComboBox.SelectedValue?
Oliver Friedrich

5
Jeśli udzielono odpowiedzi na Twoje pytanie, naprawdę powinieneś wybrać odpowiedź.
Ryan The Leach

Cel wiązania danych wyliczenia nie jest do końca jasny. Wyliczenie prawdopodobnie nie zmieni się w czasie wykonywania. Możesz również napisać metodę rozszerzenia, która wypełni kolekcję elementów combobox wszystkimi wartościami wyliczenia.
Andreas,


@OliverFriedrich SelectedValuepowoduje InvalidOperationExceptiondla mnie. „Nie można ustawić SelectedValuew a ListControlz pustym ValueMember”.
Tyler

Odpowiedzi:


161

Enum

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

Ustawienie z niego rozwijanych wartości

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

Pobieranie wyliczenia z wybranego elementu

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

5
Dzięki, to działa dla mnie. Pamiętaj, że tryparse to instrukcja .net 4.0.
real_yggdrasil

Dla mnie SelectedValue jest zawsze null. Wygląda na to, że combobox nie jest inicjalizowany. (myEnum) this.GridView.CurrentRow.Cells ["comboColumnCell"]. Wartość. Widzę wartość, ale wewnętrznie zgłasza wyjątek zerowego wskaźnika
ssal

3
To jest dokładnie sposób, którego OP nie chce używać. Problem polega na tym, że użytkownik wyświetla nazwę w kodzie każdej wartości, która często podlega refaktoryzacji i nie jest przyjazna dla użytkownika.
Alejandro

5
Dlaczego warto korzystać z TryParse zamiast Parse? ... var status (Status) Enum.Parse (typeof (Status), cbStatus.SelectedValue.ToString ()); ... Powiązałeś wyliczenie z combobox, więc WIESZ, że wartość musi być prawidłową wartością wyliczenia i jeśli wtedy coś poszło nie tak i prawdopodobnie potrzebujesz wyjątku.
bytedev

1
Dlaczego jest to uważane za zapomnienie? Pytanie brzmi, jak programowo ustawić wybraną wartość pola kombi, używając jednej z wartości wyliczenia.
Tyler

39

Ułatwiać:

Najpierw zainicjuj to polecenie: (np. Po InitalizeComponent())

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

Aby odzyskać wybrany przedmiot w Combobox:

YourEnum enum = (YourEnum) yourComboBox.SelectedItem;

Jeśli chcesz ustawić wartość dla combobox:

yourComboBox.SelectedItem = YourEnem.Foo;

2
Działa to tak długo, jak wartość wyświetlana jest taka sama jak element członkowski Value, w przeciwnym razie nie.
Lord of Scripts

15

Kod

comboBox1.SelectedItem = MyEnum.Something;

jest w porządku, problem musi znajdować się w wiązaniu danych. Przypisania DataBinding występują po konstruktorze, głównie przy pierwszym wyświetleniu pola Combo. Spróbuj ustawić wartość w zdarzeniu Load. Na przykład dodaj ten kod:

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

I sprawdź, czy działa.


12

Próbować:

comboBox1.SelectedItem = MyEnum.Something;

EDYCJE:

Ups, już tego próbowałeś. Jednak zadziałało to dla mnie, gdy mój comboBox był ustawiony jako DropDownList.

Oto mój pełny kod, który działa dla mnie (zarówno z DropDown, jak i 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;
    }
}

ciekawe, to wspaniale, że możesz zrobić `comboBox1.SelectedItem = BlahEnum.Blue;` ale co jeśli chcesz, aby rzeczy w pudełku combobox były sznurkami, np. element zestawu combobox, był „tabletką witaminową do żucia”.?
barlop

11

Powiedzmy, że masz następujące wyliczenie

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

Musisz mieć strukturę, aby zamapować te wartości na łańcuch:

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

Teraz zwróć tablicę obiektów ze wszystkimi wyliczeniami odwzorowanymi na łańcuch:

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

I użyj następujących, aby wypełnić swoje pole kombi:

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

Utwórz funkcję, aby pobrać typ wyliczenia na wypadek, gdybyś chciał przekazać go do funkcji

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

a potem powinno być dobrze :)


+1 ładne rozwiązanie. Ostatnio miałem ten sam problem i rozwiązałem go w podobny sposób (tylko za pomocą Tuplezamiast tego). Zamieniłbym zarówno wartość wyliczenia, jak i opis na właściwości, a następnie dodałbym numberCB.DisplayProperty = "Caption"; ` numberCB.ValueProperty = "Num", aby można było użyć ich SelectedValuebezpośrednio i powiązać z nim.
Alejandro

IMHO, może bardziej kompletny przykładowy kod źródłowy, jeśli też jest taka funkcjonalność, jak opcja Dodaj „Wszystko” / „Zaznacz wszystko” do ComboBox, która służy do filtrowania wszystkich wierszy w wyszukiwaniu.
Kiquenet

5

Spróbuj tego:

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

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

StoreObject to przykład mojego obiektu z właściwością StoreObjectMyEnumField dla wartości magazynu MyEnum.


1
To zdecydowanie najlepsze podejście, ale w moim przypadku nie zadziałało. Musiałem użyć „SelectedItem” zamiast „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;
    }

co masz na myśli ? Nie zrozumiałem twojego komentarza. ta metoda rozszerzenia działa
Mickey Perlstein

Zależy to od tego, czy Twoje numery wyliczeniowe zezwalają na OR FLagi. jeśli tak Możesz dodać flagę 255 o nazwie All i wywołać funkcję z All jako enum1, co tworzy wartość domyślną. tj. comboBox1.FillByEnumOrderByName (MyEnum.All)
Mickey Perlstein

Każda opcja taka jak ta: var l = values.OrderBy (x => x.Value) .ToList (); l.Insert (0, "Wszystko");
Kiquenet

moje wyliczenie to wyliczenie A {kaczka = 0, łabędź = 1, joker = 3}; Twój system nie będzie działał w mojej sytuacji.
Mickey Perlstein

3

to jest rozwiązanie do załadowania elementu wyliczenia w combobox:

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

Następnie użyj wyliczenia jako tekstu:

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

3

Na podstawie odpowiedzi od @Amir Shenouda kończy się na tym:

Definicja Enuma:

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

Ustawianie z niego rozwijanych wartości:

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

Pobieranie wyliczenia z wybranego elementu:

Status? status = cbStatus.SelectedValue as Status?;

2
dlaczego używać wartości null? Możesz użyć rzutowania jawnego (rzutowania nawiasów) i nie używać wartości null
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, może bardziej kompletny przykładowy kod źródłowy, jeśli też jest taka funkcjonalność, jak opcja Dodaj „Wszystko” / „Zaznacz wszystko” do ComboBox, która służy do filtrowania wszystkich wierszy w wyszukiwaniu.
Kiquenet


1

Używam następującej metody pomocniczej, którą możesz powiązać ze swoją listą.

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

Przekonwertuj wyliczenie na listę ciągów i dodaj ją do comboBox

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

Ustaw wyświetlaną wartość za pomocą selectedItem

comboBox1.SelectedItem = SomeEnum.SomeValue;

1

Żadne z nich nie zadziałało dla mnie, ale zadziałało (i miało dodatkową zaletę w postaci lepszego opisu nazwy każdego wyliczenia). Nie jestem pewien, czy jest to spowodowane aktualizacjami .net, czy nie, ale niezależnie od tego uważam, że to najlepszy sposób. Musisz dodać odniesienie do:

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

Następnie, jeśli chcesz uzyskać dostęp do danych, użyj tych dwóch linii:

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

1

Prawdopodobnie nigdy nie będzie to widoczne wśród wszystkich innych odpowiedzi, ale to jest kod, który wymyśliłem, ma tę zaletę, że używa się, DescriptionAttributejeśli istnieje, ale w przeciwnym razie używa się nazwy samej wartości wyliczenia.

Użyłem słownika, ponieważ ma on gotowy wzorzec pozycji klucz / wartość. A List<KeyValuePair<string,object>>działałby również bez niepotrzebnego haszowania, ale słownik zapewnia czystszy kod.

Mam członków, którzy mają wartość „ MemberTypeof” Fieldi „dosłownie”. Spowoduje to utworzenie sekwencji tylko członków, które są wartościami wyliczeniowymi. Jest to niezawodne, ponieważ wyliczenie nie może mieć innych pól.

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;

powinno działać dobrze ... Jak możesz stwierdzić, że SelectedItemto jest zerowe?


Mogę to sprawdzić w debugerze. Zakładam, że dzieje się tak, ponieważ typ SelectedItem jest object, tj. Typ referencyjny, a wyliczenia są typami wartości. Chociaż spodziewałbym się, że kompilator to złapie.

0

Możesz użyć funkcji „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

Możesz użyć listy wartości KeyValuePair jako źródła danych dla combobox. Będziesz potrzebować metody pomocniczej, w której możesz określić typ wyliczenia i zwraca IEnumerable>, gdzie int jest wartością wyliczenia, a string to nazwa wartości wyliczenia. W polu combobox ustaw właściwość DisplayMember na „Klucz”, a właściwość ValueMember na „Wartość”. Wartość i klucz to właściwości publiczne struktury KeyValuePair. Następnie, gdy ustawisz właściwość SelectedItem na wartość wyliczenia, tak jak robisz, powinno to działać.


0

W tej chwili używam właściwości Items, a nie DataSource, oznacza to, że muszę wywołać Add dla każdej wartości wyliczenia, ale i tak jest to małe wyliczenie i jego tymczasowy kod.

Następnie mogę po prostu wykonać Convert.ToInt32 na wartości i ustawić ją za pomocą SelectedIndex.

Rozwiązanie tymczasowe, ale na razie YAGNI.

Pozdrawiam pomysły, prawdopodobnie skorzystam z nich, kiedy zrobię odpowiednią wersję po otrzymaniu serii opinii klientów.



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

comboBox1.SelectedIndex = (int)MyEnum.Something;

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

Obie te metody działają dla mnie. Jesteś pewien, że coś innego jest nie tak?


2
Nie jestem pewien, czy to zadziała, jeśli użyjesz niestandardowych wartości wyliczenia, np.enum MyEnum { Something = 47 }
Samantha Branham

0

Ogólna metoda ustawiania wyliczenia jako źródła danych dla listy rozwijanej

Wyświetlana byłaby nazwa. Wybraną wartością będzie samo 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

To zawsze był problem. jeśli masz Sorted Enum, np. od 0 do ...

public enum Test
      one
      Two
      Three
 End

możesz powiązać nazwy z combobox i zamiast używać .SelectedValuewłaściwości.SelectedIndex

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

i

Dim x as byte = 0
Combobox.Selectedindex=x

0

W Framework 4 możesz użyć następującego kodu:

Aby powiązać wyliczenie MultiColumnMode z combobox, na przykład:

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

i aby uzyskać wybrany indeks:

MultiColumnMode multiColMode = (MultiColumnMode)cbMultiColumnMode.SelectedIndex;

uwaga: w tym przykładzie używam DevExpress ComboBox, możesz zrobić to samo w Win Form Combobox


0

Trochę za późno na tę imprezę,

Metoda SelectedValue.ToString () powinna pobierać DisplayedName. Jednak ten artykuł DataBinding Enum, a także With Descriptions pokazuje wygodny sposób, aby nie tylko to mieć, ale zamiast tego możesz dodać niestandardowy atrybut opisu do wyliczenia i użyć go dla wyświetlanej wartości, jeśli wolisz. Bardzo prosty i łatwy, zawiera około 15 linii kodu (chyba że policzysz nawiasy klamrowe) na wszystko.

Jest to całkiem sprytny kod i możesz uczynić go metodą rozszerzenia do uruchamiania ...


0

używaj odlewania tylko w ten sposób:

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

0

Możesz użyć metody rozszerzenia

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

Jak używać ... Zadeklaruj wyliczenie

using System.ComponentModel;

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

Ta metoda wyświetla opis w elementach listy rozwijanej

combobox1.EnumForComboBox(typeof(CalculationType));

0

To zadziałało dla mnie:

comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
comboBox1.SelectedIndex = comboBox1.FindStringExact(MyEnum.something.ToString());
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.