Привязка перечисления к полю со списком 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
Если на ваш вопрос был дан ответ, вам действительно следует выбрать ответ.
Ryan The Leach

Суть привязки перечисления к данным не совсем ясна. Скорее всего, перечисление не изменится во время выполнения. Вы также можете написать метод расширения, который заполнял бы коллекцию элементов combobox всеми значениями перечисления.
Андреас


@OliverFriedrich SelectedValueвызывает InvalidOperationExceptionу меня. "Невозможно установить SelectedValueв a ListControlс пустым ValueMember".
Тайлер

Ответы:


161

Enum

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

Установка выпадающих значений из него

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

Получение перечисления из выбранного элемента

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

5
Спасибо, у меня работает Имейте в виду, что tryparse - это заявление .net 4.0.
real_yggdrasil

Для меня SelectedValue всегда равно нулю. Кажется, что поле со списком не инициализируется. (MyEnum) this.GridView.CurrentRow.Cells [ "comboColumnCell"]. значение. Я вижу значение, но внутри он выдает исключение с нулевым указателем
ssal

3
Это именно тот способ, которым OP не хочет пользоваться. Проблема в том, что пользователю отображается имя в коде каждого значения, которое подлежит рефакторингу и в большинстве случаев не является удобным для пользователя.
Алехандро

5
Зачем использовать TryParse, а не Parse? ... var status (Status) Enum.Parse (typeof (Status), cbStatus.SelectedValue.ToString ()); ... Вы связали перечисление с полем со списком, поэтому ЗНАЕТЕ, что значение должно быть допустимым значением перечисления, и если это не значит, что что-то пошло не так, и вам, вероятно, нужно исключение.
bytedev 06

1
Почему это предано забвению? Вопрос в том, как программно установить выбранное значение поля со списком, используя одно из значений перечисления.
Тайлер

39

Для упрощения:

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

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

Чтобы получить выбранный элемент в поле со списком:

YourEnum enum = (YourEnum) yourComboBox.SelectedItem;

Если вы хотите установить значение для поля со списком:

yourComboBox.SelectedItem = YourEnem.Foo;

2
Это работает до тех пор, пока значение Display совпадает с элементом Value, в противном случае - нет.
Lord of Scripts

15

Код

comboBox1.SelectedItem = MyEnum.Something;

в порядке, проблема должна быть в DataBinding. Назначения DataBinding происходят после конструктора, в основном при первом отображении поля со списком. Попробуйте установить значение в событии Load. Например, добавьте этот код:

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;`, но что если вы хотите, чтобы элементы в поле со списком были строками, например, элементом поля со списком была «жевательная витаминная таблетка»?
barlop

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());

Создайте функцию для получения типа перечисления на тот случай, если вы хотите передать его функции

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

и тогда все будет в порядке :)


+1 красивое решение. Недавно была эта проблема и решена аналогичным образом (только Tupleвместо этого). Я бы превратил значение перечисления и описание в свойства, а затем добавил бы numberCB.DisplayProperty = "Caption"; `и numberCB.ValueProperty = "Num"так, чтобы вы могли использовать его SelectedValueнапрямую и привязать к нему.
Алехандро

IMHO, может быть, более полный образец исходного кода, если тоже есть такие функции, как «Добавить все» / «Выбрать все» в ComboBox, используемую для фильтрации всех строк в поиске.
Kiquenet

5

Попробуй это:

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

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

StoreObject - это мой пример объекта со свойством StoreObjectMyEnumField для хранения значения MyEnum.


1
Это, безусловно, лучший подход, но пока он не сработал для меня. Мне пришлось использовать «SelectedItem» вместо «SelectedValue»
Тьяго Фрейтас Леаль

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

что вы имеете в виду ? Я не понял вашего комментария. этот метод расширения работает
Микки Перлштейн

Это зависит от того, разрешают ли ваши числа перечисления ИЛИ флаги. если да, то вы можете добавить флаг 255 с именем All и вызвать функцию с All как enum1, что создает значение по умолчанию. ie comboBox1.FillByEnumOrderByName (MyEnum.All)
Микки Перлштейн,

Любой такой вариант: var l = values.OrderBy (x => x.Value) .ToList (); l.Insert (0, «Все»);
Kiquenet

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

3

это решение для загрузки элемента перечисления в поле со списком:

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

А затем используйте элемент перечисления как текст:

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

3

Основываясь на ответе @Amir Shenouda, я получаю следующее:

Определение Enum:

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

Установка выпадающих значений из него:

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

Получение перечисления из выбранного элемента:

Status? status = cbStatus.SelectedValue as Status?;

2
зачем использовать nullable? Вы можете использовать явное приведение (приведение скобок) и не использовать обнуляемое значение
Джон Деметриу,

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, используемую для фильтрации всех строк в поиске.
Kiquenet


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

Преобразуйте перечисление в список строк и добавьте его в comboBox

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

Установите отображаемое значение с помощью selectedItem

comboBox1.SelectedItem = SomeEnum.SomeValue;

1

Ни один из них не сработал для меня, но это сработало (и у него было дополнительное преимущество, заключающееся в возможности иметь лучшее описание для имени каждого перечисления). Я не уверен, связано ли это с обновлениями .net или нет, но, тем не менее, я считаю, что это лучший способ. Вам нужно будет добавить ссылку на:

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

Затем, когда вы хотите получить доступ к данным, используйте эти две строки:

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

1

Вероятно, этого никогда не будет видно среди всех других ответов, но это код, который я придумал, его преимущество заключается в использовании, DescriptionAttributeесли он существует, но в противном случае с использованием имени самого значения перечисления.

Я использовал словарь, потому что в нем есть готовый шаблон элемента ключ / значение. 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 в качестве источника данных для поля со списком. Вам понадобится вспомогательный метод, в котором вы можете указать тип перечисления, и он возвращает IEnumerable>, где int - это значение перечисления, а строка - это имя значения перечисления. В поле со списком установите для свойства DisplayMember значение «Key», а для свойства ValueMember - значение «Value». Value и Key - это общедоступные свойства структуры KeyValuePair. Затем, когда вы устанавливаете для свойства SelectedItem значение перечисления, как вы это делаете, оно должно работать.


0

На данный момент я использую свойство Items, а не DataSource, это означает, что мне нужно вызывать Add для каждого значения перечисления, но это небольшое перечисление и его временный код в любом случае.

Затем я могу просто выполнить Convert.ToInt32 для значения и установить его с помощью SelectedIndex.

Временное решение, но пока ЯГНИ.

Приветствую вас за идеи, я, вероятно, воспользуюсь ими, когда сделаю правильную версию после того, как получу отзывы клиентов.


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 MyEnum { Something = 47 }
Саманта Бранхам,

0

Универсальный метод установки перечисления в качестве источника данных для раскрывающихся списков

Отображение будет именем. Выбранное значение будет само 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

Это всегда было проблемой. если у вас есть Sorted Enum, например от 0 до ...

public enum Test
      one
      Two
      Three
 End

вы можете привязать имена к combobox и вместо использования .SelectedValueсвойства использовать.SelectedIndex

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

и

Dim x as byte = 0
Combobox.Selectedindex=x

0

В Framework 4 вы можете использовать следующий код:

Чтобы привязать перечисление MultiColumnMode к combobox, например:

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

и получить выбранный индекс:

MultiColumnMode multiColMode = (MultiColumnMode)cbMultiColumnMode.SelectedIndex;

примечание: в этом примере я использую поле со списком DevExpress, вы можете сделать то же самое в поле со списком Win Form


0

Немного поздно на эту вечеринку,

Метод SelectedValue.ToString () должен извлекать DisplayedName. Однако эта статья DataBinding Enum, а также With Descriptions показывает удобный способ не только иметь это, но вместо этого вы можете добавить настраиваемый атрибут описания в перечисление и использовать его для отображаемого значения, если хотите. Очень просто и легко и около 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
}

Описание этого метода отображается в элементах поля со списком

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.