Прив’яжіть перерахунок до комбінованого вікна WinForms та встановіть його


122

багато людей відповіли на питання, як прив’язати перерахунок до комбінованого вікна в WinForms. Це так:

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

Але це досить марно, не маючи можливості встановити фактичне значення для відображення.

Я намагався:

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

Я також спробував:

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

Хтось має ідеї, як це зробити?


2
Чому б просто не спробувати ComboBox.SelectedValue?
Олівер Фрідріх

5
Якщо на ваше запитання відповіли, вам дійсно слід вибрати відповідь.
Райан Ліч

Точка зв’язування даних перерахунку не зовсім зрозуміла. Перерахунок, ймовірно, не зміниться під час виконання. Ви також можете написати метод розширення, який би заповнював колекцію елементів комбінації усіма значеннями перерахунків.
Андреас


@OliverFriedrich SelectedValueвикликає InvalidOperationExceptionдля мене. Msgstr "Неможливо встановити значення SelectedValueв ListControlпорожній ValueMember."
Тайлер

Відповіді:


161

Енум

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

Встановлення спадних значень з нього

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

Отримання перерахунку з вибраного елемента

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

5
Дякую, це працює для мене. Майте на увазі, трипарсе - це .net 4.0.
real_yggdrasil

Для мене SelectedValue завжди є недійсним. Здається, комбобокс не отримує ідеалізації. (myEnum) this.GridView.CurrentRow.Cells ["comboColumnCell"]. Значення. Я бачу значення, але внутрішньо він кидає нульовий виняток вказівника
ssal

3
Це саме той спосіб, який ОП не хоче використовувати. Проблема полягає в тому, що користувачеві відображається ім'я в коді кожного значення, яке підлягає рефакторингу і не є зручним для користувачів більшість разів.
Алехандро

5
Навіщо використовувати TryParse, а не Parse? ... var status (Статус) Enum.Parse (typeof (Статус), cbStatus.SelectedValue.ToString ()); ... Ви прив’язуєте enum до комбінованої скриньки, тож Ви знаєте, що значення повинно бути дійсним значенням enum, і якщо це не тоді щось пішло не так, і ви, мабуть, хочете виключення.
bytedev

1
Чому це прихильне до забуття? Питання полягає в тому, як програматично встановити вибране значення комбобоксу, використовуючи одне із значень enum.
Тайлер

39

Щоб спростити:

Спочатку ініціалізуйте цю команду: (наприклад, після InitalizeComponent())

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

Щоб отримати вибраний елемент у комбоботі:

YourEnum enum = (YourEnum) yourComboBox.SelectedItem;

Якщо ви хочете встановити значення для комбобоксу:

yourComboBox.SelectedItem = YourEnem.Foo;

2
Це працює до тих пір, поки значення відображення є таким самим, як член Значення, інакше ні.
Володар сценаріїв

15

Код

comboBox1.SelectedItem = MyEnum.Something;

це нормально, проблема повинна полягати в прив'язці даних. Призначення прив'язки даних відбуваються після конструктора, в основному вперше, коли відображається комбіноване поле. Спробуйте встановити значення в події "Завантажити". Наприклад, додайте цей код:

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

І перевірте, чи працює.


12

Спробуйте:

comboBox1.SelectedItem = MyEnum.Something;

ЗМІНИ:

Ну, ви вже пробували це. Однак, для мене це спрацювало, коли мій comboBox був встановлений як DropDownList.

Ось мій повний код, який працює для мене (і з DropDown, і з 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;
    }
}

Що цікаво, це чудово, що ви можете зробити `comboBox1.SelectedItem = BlahEnum.Blue;` але що робити, якщо ви хочете, щоб речі в комбобоні були рядками, наприклад, елемент комбобоксу був «жувальною вітамінною таблеткою»?
барлоп

11

Скажімо, у вас є наступний перелік

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

Вам потрібно мати структуру для відображення цих значень у рядок:

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

Тепер поверніть масив об'єктів із усіма перерахунками, відображеними у рядку:

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

А для заповнення комбінованого вікна скористайтеся наступним:

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

Створіть функцію для виведення типу enum у випадку, якщо ви хочете передати його функції

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

і тоді вам повинно бути гаразд :)


+1 приємне рішення. Нещодавно виникла ця сама проблема і вона вирішилася аналогічно (лише Tupleзамість цього). Я перетворив би значення enum та опис у властивості, а потім додав a numberCB.DisplayProperty = "Caption"; `і numberCB.ValueProperty = "Num"так, що ви можете SelectedValueбезпосередньо використовувати та прив’язувати до нього.
Алехандро

IMHO, можливо, більш повний зразок вихідного коду, якщо теж є функціональність, наприклад, опція Додати "Все" / "Вибрати все" в ComboBox, що використовується для фільтрації всіх рядків у пошуку.
Кікенет

5

Спробуйте це:

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

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

StoreObject - мій об'єктний приклад із властивістю StoreObjectMyEnumField для зберігання значення MyEnum.


1
Це найкращий підхід на сьогодні, але, як це є, він не працював для мене. Мені довелося використовувати "SelectedItem" замість "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;
    }

Що ви маєте на увазі ? Я не зрозумів вашого коментаря. цей метод розширення працює
Міккі Перлштайн

Це залежить від того, чи дозволяють ваші цифри перерахувань АБО FLAgs. якщо так, Ви можете додати прапор, який називається All (255), і зателефонувати на функцію "All" як enum1, що створює за замовчуванням. тобто comboBox1.FillByEnumOrderByName (MyEnum.All)
Міккі Перлштайн

Будь-який варіант на зразок цього: var l = values.OrderBy (x => x.Value) .ToList (); l.Insert (0, "Усі");
Кікенет

мій перелік - перерахунок A {качка = 0, лебідь = 1, жарт = 3}; ваша система не працюватиме для моєї ситуації.
Міккі Перлштайн

3

це рішення для завантаження елемента enum у комбіновану скриньку:

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

А потім використовуйте елемент enum як текст:

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

3

На основі відповіді від @Amir Shenouda я закінчую це:

Визначення Енума:

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

Встановлення спадних значень з нього:

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

Отримання перерахунку з вибраного елемента:

Status? status = cbStatus.SelectedValue as Status?;

2
навіщо використовувати нульові? Ви можете використовувати явний кастинг (лиття в дужках), а не використовувати нульовий
Джон Деметріу

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, можливо, більш повний зразок вихідного коду, якщо теж є функціональність, наприклад, опція Додати "Все" / "Вибрати все" в ComboBox, що використовується для фільтрації всіх рядків у пошуку.
Кікенет


1

Я використовую такий допоміжний метод, який ви можете прив’язати до свого списку.

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

Перетворіть перерахунок у список рядків та додайте це до комбі-боксу

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

Встановіть відображене значення за допомогою selectedItem

comboBox1.SelectedItem = SomeEnum.SomeValue;

1

Жодне з них не працювало для мене, але це зробило (і це було додатковою перевагою, щоб мати кращий опис для імені кожного перерахунку). Я не впевнений, це пов’язано з оновленнями .net чи ні, але незалежно від того, я думаю, це найкращий спосіб. Вам потрібно буде додати посилання на:

за допомогою 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";
    }

Потім, коли ви хочете отримати доступ до даних, використовуйте ці два рядки:

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

1

Це, мабуть, ніколи не буде помічено серед усіх інших відповідей, але це код, який я придумав, для цього є користь використання параметра DescriptionAttributeif, якщо він існує, але в іншому випадку використання імені самого значення enum.

Я використав словник, тому що він має готовий шаблон ключа / значення. A List<KeyValuePair<string,object>>також працює і без зайвого хешування, але словник створює більш чистий код.

Я отримую членів , які мають MemberTypeз Fieldі які є буквальним. Це створює послідовність лише членів, які мають значення перерахунків. Це надійно, оскільки перерахунок не може мати інших полів.

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;

має працювати просто чудово ... Як ви можете сказати, що SelectedItemце недійсно?


Я можу перевірити це в налагоджувачі. Я припускаю, що це тому, що тип SelectedItem є об'єктом, тобто типом посилання, а перерахунки - типовими типами. Хоча я б очікував, що компілятор це схопить.

0

Ви можете використовувати функції "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

Ви можете використовувати список значень KeyValuePair як джерело даних для комбінованого списку. Вам знадобиться допоміжний метод, де ви можете вказати тип enum, і він повертає IEnumerable> де int - значення enum, а рядок - це ім'я значення enum. У комбінаційному вікні встановіть для властивості DisplayMember значення «Ключ», а для властивості ValueMember - «Значення». Значення та ключ - це загальнодоступні властивості структури KeyValuePair. Потім, коли ви встановите для властивості SelectedItem значення enum, як ви робите, воно повинно працювати.


0

На даний момент я використовую властивість Item, а не DataSource, це означає, що я повинен викликати Додати для кожного значення enum, але його невелике перерахування і тимчасовий код все одно.

Тоді я можу просто зробити Convert.ToInt32 за значенням і встановити його за допомогою SelectedIndex.

Тимчасове рішення, але YAGNI поки що.

Вітаю за ідеї, я, мабуть, їх використовуватиму, коли буду робити належну версію після отримання відгуку клієнтів.


0

Можливо, тут було старе питання, але у мене виникла проблема, і рішення було легко і просто, я знайшов це http://www.c-sharpcorner.com/UploadFile/mahesh/1220/

Він використовує обмін даними і прекрасно працює, тому перевірте це.


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

comboBox1.SelectedIndex = (int)MyEnum.Something;

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

Обидва ці роботи для мене ви впевнені, що щось інше не так?


2
Не впевнений, що це спрацює, якщо використовувати спеціальні значення enum, тобтоenum MyEnum { Something = 47 }
Саманта Бранхем,

0

Загальний метод встановлення enum як джерела даних для спадів

Дисплей буде ім'ям. Вибране значення було б самою 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

Це завжди було проблемою. якщо у вас є відсортований Enum, наприклад від 0 до ...

public enum Test
      one
      Two
      Three
 End

ви можете прив’язувати імена до комбінованої скриньки та замість того, щоб використовувати .SelectedValueвластивості.SelectedIndex

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

і

Dim x as byte = 0
Combobox.Selectedindex=x

0

У Framework 4 ви можете використовувати такий код:

Наприклад, щоб прив’язати перерахунок MultiColumnMode до комбобота, наприклад:

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

і щоб отримати вибраний індекс:

MultiColumnMode multiColMode = (MultiColumnMode)cbMultiColumnMode.SelectedIndex;

Примітка: я використовую комбінацію DevExpress у цьому прикладі, ви можете зробити те ж саме у програмі Win Form Combobox


0

Трохи запізнюючись на цю вечірку,

Метод SelectedValue.ToString () повинен містити DisplayedName. Однак ця стаття Enbinding Enum, а також "Описи" показує зручний спосіб не тільки мати це, але натомість ви можете додати до enum атрибути спеціального опису і використовувати його для відображуваного значення, якщо вам зручніше. Дуже простий і простий і близько 15 рядків або близько коду (якщо не рахувати фігурні дужки) для всього.

Це досить вишуканий код, і ви можете зробити його методом розширення для завантаження ...


0

використовуйте лише кастинг таким чином:

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

0

Можна використовувати метод розширення

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

Як користуватися ... Оголосити перерахунок

using System.ComponentModel;

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

Цей спосіб відобразити опис у елементах поля Combo

combobox1.EnumForComboBox(typeof(CalculationType));

0

Це працювало для мене:

comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
comboBox1.SelectedIndex = comboBox1.FindStringExact(MyEnum.something.ToString());
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.