ComboBox: добавление текста и значения к элементу (без источника привязки)

202

В C # WinApp, как я могу добавить текст и значение для элементов моего ComboBox? Я выполнил поиск, и обычно в ответах используется «Привязка к источнику» ... но в моем случае у меня нет готового источника привязки в моей программе ... Как я могу сделать что-то вроде этого:

combo1.Item[1] = "DisplayText";
combo1.Item[1].Value = "useful Value"
Bohn
источник

Ответы:

361

Вы должны создать свой собственный тип класса и переопределить метод ToString (), чтобы вернуть нужный текст. Вот простой пример класса, который вы можете использовать:

public class ComboboxItem
{
    public string Text { get; set; }
    public object Value { get; set; }

    public override string ToString()
    {
        return Text;
    }
}

Ниже приведен простой пример его использования:

private void Test()
{
    ComboboxItem item = new ComboboxItem();
    item.Text = "Item text1";
    item.Value = 12;

    comboBox1.Items.Add(item);

    comboBox1.SelectedIndex = 0;

    MessageBox.Show((comboBox1.SelectedItem as ComboboxItem).Value.ToString());
}
Адам Марковиц
источник
4
нужен ли нам этот новый класс ComboboxItem? Я думаю, что уже существует один, который называется ListItem.
Амр Элгархи
15
Я считаю, что может быть доступно только в ASP.NET, а не WinForms.
Адам Марковиц
1
Нет. Элемент - это отдельный тип, который используется только для хранения данных элементов (текст, значение, ссылки на другие объекты и т. Д.). Он не является потомком ComboBox, и это было бы крайне редко.
Адам Марковиц
1
Я знаю, что я немного опоздал на вечеринку, но как я это сделал в чистой форме Windows Window, так это настроить таблицу данных, добавить к ней элементы и привязать комбинированный список к таблице данных. Можно было бы подумать, что должен быть более чистый способ сделать это, но я не нашел его (DisplayMember - это свойство в выпадающем списке, которое нужно для отображения текста, ValueMember для значения данных)
user2366842
4
как мы можем получить "SelectedValue" или выбрать элемент на основе значения ... пожалуйста, ответьте
Альфа Габриэль В. Тимбол
185
// Bind combobox to dictionary
Dictionary<string, string>test = new Dictionary<string, string>();
        test.Add("1", "dfdfdf");
        test.Add("2", "dfdfdf");
        test.Add("3", "dfdfdf");
        comboBox1.DataSource = new BindingSource(test, null);
        comboBox1.DisplayMember = "Value";
        comboBox1.ValueMember = "Key";

// Get combobox selection (in handler)
string value = ((KeyValuePair<string, string>)comboBox1.SelectedItem).Value;
потрясающий
источник
2
Работает отлично, и это должен быть выбранный ответ. Но мы не можем использовать comboBox1.SelectedText вместо приведения .SelectedItem и взять .Value?
Джеффри Гойнс
@fab как найти элемент в выпадающем списке с определенным ключом
Смит,
Можно ли выбрать элемент в выпадающем списке по ключу словаря? Как выбрать ключ 3, поэтому будет выбран пункт с ключом 3.
Дрор
Этот метод больше не работает для vs2015. Исключения из-за невозможности привязки к новому отображаемому элементу и Valuemember
Plater
119

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

comboBox.DisplayMember = "Text";
comboBox.ValueMember = "Value";

comboBox.Items.Add(new { Text = "report A", Value = "reportA" });
comboBox.Items.Add(new { Text = "report B", Value = "reportB" });
comboBox.Items.Add(new { Text = "report C", Value = "reportC" });
comboBox.Items.Add(new { Text = "report D", Value = "reportD" });
comboBox.Items.Add(new { Text = "report E", Value = "reportE" });

ОБНОВЛЕНИЕ: Хотя приведенный выше код будет правильно отображаться в поле со списком, вы не сможете использовать SelectedValueили SelectedTextсвойства ComboBox. Чтобы использовать их, свяжите поле со списком, как показано ниже:

comboBox.DisplayMember = "Text";
comboBox.ValueMember = "Value";

var items = new[] { 
    new { Text = "report A", Value = "reportA" }, 
    new { Text = "report B", Value = "reportB" }, 
    new { Text = "report C", Value = "reportC" },
    new { Text = "report D", Value = "reportD" },
    new { Text = "report E", Value = "reportE" }
};

comboBox.DataSource = items;
buhtla
источник
14
Я хотел бы немного изменить это, потому что программисту, вероятно, понадобится цикл for вместе с этим. Вместо массива я использовал список. List<Object> items = new List<Object>(); Затем я смог использовать метод items.Add( new { Text = "report A", Value = "reportA" } );внутри цикла.
Андрей
1
Эндрю, вы заставили List <Object> работать со свойством SelectedValue?
Питер Питлок
@Venkat,comboBox.SelectedItem.GetType().GetProperty("Value").GetValue(comboBox.SelectedItem, null)
Оптавиус
2
@Venkat, если вы используете второе решение, которое устанавливает, DataSourceвы можете использовать свойства SelectedValueили SelectedTextполя со списком, поэтому нет необходимости выполнять какое-либо специальное приведение.
JPProgrammer
32

Вы должны использовать dynamicобъект для разрешения элемента комбинированного списка во время выполнения.

comboBox.DisplayMember = "Text";
comboBox.ValueMember = "Value";

comboBox.Items.Add(new { Text = "Text", Value = "Value" });

(comboBox.SelectedItem as dynamic).Value
Мерт Чингоз
источник
1
Это намного лучше, чем создание отдельного класса и переопределение ToString ().
Дон Шрут
1
динамический доступен только в C # 4 и выше. (Я думаю, .NET 4.5)
MickeyfAgain_BeforeExitOfSO
Просто и быстрее писать! Я сделал это для SelectedValue в VB.net: Dim Value As String = CType (Me.SectionIDToComboBox.SelectedItem, Object) .Value
Ханнингтон Мамбо
1
Как же тогда установить правильный элемент комбинированного списка, используя «Значение»?
Дейв Людвиг
17

Вы можете использовать DictionaryObject вместо создания пользовательского класса для добавления текста и значения вCombobox .

Добавить ключи и значения в Dictionaryобъекте:

Dictionary<string, string> comboSource = new Dictionary<string, string>();
comboSource.Add("1", "Sunday");
comboSource.Add("2", "Monday");

Привязать исходный объект Dictionary к Combobox:

comboBox1.DataSource = new BindingSource(comboSource, null);
comboBox1.DisplayMember = "Value";
comboBox1.ValueMember = "Key";

Получить ключ и значение:

string key = ((KeyValuePair<string,string>)comboBox1.SelectedItem).Key;
string value = ((KeyValuePair<string,string>)comboBox1.SelectedItem).Value;

Полный Источник: Combobox Text nd Value

cronynaval
источник
14

Это один из способов, который только что пришел в голову:

combo1.Items.Add(new ListItem("Text", "Value"))

И чтобы изменить текст или значение элемента, вы можете сделать это так:

combo1.Items[0].Text = 'new Text';

combo1.Items[0].Value = 'new Value';

В Windows Forms нет класса ListItem . Он существует только в ASP.NET , поэтому вам нужно будет написать собственный класс перед его использованием, так же, как @Adam Markowitz в своем ответе .

Также проверьте эти страницы, они могут помочь:

Амр Элгархи
источник
2
Если я не ошибаюсь, ListItem доступен только в ASP.NET
Адам Марковиц
да :( к сожалению, это только в ASP.net ... так что я могу сделать сейчас?
Бон
Тогда в чем смысл свойств SelectedValue или SelectedText в комбинированном списке?
JSON
11

Не знаю, сработает ли это для ситуации, описанной в оригинальном посте (не говоря уже о том, что это два года спустя), но этот пример работает для меня:

Hashtable htImageTypes = new Hashtable();
htImageTypes.Add("JPEG", "*.jpg");
htImageTypes.Add("GIF", "*.gif");
htImageTypes.Add("BMP", "*.bmp");

foreach (DictionaryEntry ImageType in htImageTypes)
{
    cmbImageType.Items.Add(ImageType);
}
cmbImageType.DisplayMember = "key";
cmbImageType.ValueMember = "value";

Чтобы вывести свое значение обратно, вам нужно привести свойство SelectedItem к объекту DictionaryEntry, а затем вы можете оценить его свойства Key и Value. Например:

DictionaryEntry deImgType = (DictionaryEntry)cmbImageType.SelectedItem;
MessageBox.Show(deImgType.Key + ": " + deImgType.Value);
ChuckG
источник
7
//set 
comboBox1.DisplayMember = "Value"; 
//to add 
comboBox1.Items.Add(new KeyValuePair("2", "This text is displayed")); 
//to access the 'tag' property 
string tag = ((KeyValuePair< string, string >)comboBox1.SelectedItem).Key; 
MessageBox.Show(tag);
Райан
источник
5

Если кому-то все еще интересно это, вот простой и гибкий класс для элемента комбинированного списка с текстом и значением любого типа (очень похоже на пример Адама Марковица):

public class ComboBoxItem<T>
{
    public string Name;
    public T value = default(T);

    public ComboBoxItem(string Name, T value)
    {
        this.Name = Name;
        this.value = value;
    }

    public override string ToString()
    {
        return Name;
    }
}

Использование <T>лучше, чем объявление valueкак object, потому что сobject что тогда вам придется отслеживать тип, который вы использовали для каждого элемента, и приводить его в свой код, чтобы использовать его правильно.

Я уже давно использую его в своих проектах. Это действительно удобно.

Матеус Роча
источник
4

Мне понравился ответ fab, но я не хотел использовать словарь для моей ситуации, поэтому я заменил список кортежей.

// set up your data
public static List<Tuple<string, string>> List = new List<Tuple<string, string>>
{
  new Tuple<string, string>("Item1", "Item2")
}

// bind to the combo box
comboBox.DataSource = new BindingSource(List, null);
comboBox.ValueMember = "Item1";
comboBox.DisplayMember = "Item2";

//Get selected value
string value = ((Tuple<string, string>)queryList.SelectedItem).Item1;
Мэгги
источник
3

Пример использования DataTable:

DataTable dtblDataSource = new DataTable();
dtblDataSource.Columns.Add("DisplayMember");
dtblDataSource.Columns.Add("ValueMember");
dtblDataSource.Columns.Add("AdditionalInfo");

dtblDataSource.Rows.Add("Item 1", 1, "something useful 1");
dtblDataSource.Rows.Add("Item 2", 2, "something useful 2");
dtblDataSource.Rows.Add("Item 3", 3, "something useful 3");

combo1.Items.Clear();
combo1.DataSource = dtblDataSource;
combo1.DisplayMember = "DisplayMember";
combo1.ValueMember = "ValueMember";

   //Get additional info
   foreach (DataRowView drv in combo1.Items)
   {
         string strAdditionalInfo = drv["AdditionalInfo"].ToString();
   }

   //Get additional info for selected item
    string strAdditionalInfo = (combo1.SelectedItem as DataRowView)["AdditionalInfo"].ToString();

   //Get selected value
   string strSelectedValue = combo1.SelectedValue.ToString();
Soenhay
источник
3

Вы можете использовать этот код для вставки некоторых элементов в комбинированное окно с текстом и значением.

C #

private void ComboBox_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
    combox.Items.Insert(0, "Copenhagen");
    combox.Items.Insert(1, "Tokyo");
    combox.Items.Insert(2, "Japan");
    combox.Items.Insert(0, "India");   
}

XAML

<ComboBox x:Name="combox" SelectionChanged="ComboBox_SelectionChanged_1"/>
Мухаммед Ахмад
источник
Пожалуйста, объясните ваше решение.
Вайбхав Баджай
Просто добавьте следующие страны в соответствующие индексы в поле со списком. При запуске. Появится поле с параметром 0 index. Если щелкнуть поле, появится следующий параметр
Мухаммед Ахмад
это не работа для идентификаторов это просто способ индексации списка, это не то , что речь шла о
г - н HEELIS
2

В дополнение к ответу Адама Марковица, здесь представлен универсальный способ (относительно) простого задания ItemSourceзначений поля со списком enums, при этом показывая атрибут «Описание» пользователю. (Вы можете подумать, что все захотят сделать это так, чтобы это был .NET- лайнер, но это не так, и это самый элегантный способ, который я нашел).

Сначала создайте этот простой класс для преобразования любого значения Enum в элемент ComboBox:

public class ComboEnumItem {
    public string Text { get; set; }
    public object Value { get; set; }

    public ComboEnumItem(Enum originalEnum)
    {
        this.Value = originalEnum;
        this.Text = this.ToString();
    }

    public string ToString()
    {
        FieldInfo field = Value.GetType().GetField(Value.ToString());
        DescriptionAttribute attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
        return attribute == null ? Value.ToString() : attribute.Description;
    }
}

Во-вторых, в вашем OnLoadобработчике событий вы должны установить источник вашего поля со списком, чтобы быть списком, ComboEnumItemsоснованным на каждом Enumв вашем Enumтипе. Это может быть достигнуто с Linq. Затем просто установите DisplayMemberPath:

    void OnLoad(object sender, RoutedEventArgs e)
    {
        comboBoxUserReadable.ItemsSource = Enum.GetValues(typeof(EMyEnum))
                        .Cast<EMyEnum>()
                        .Select(v => new ComboEnumItem(v))
                        .ToList();

        comboBoxUserReadable.DisplayMemberPath = "Text";
        comboBoxUserReadable.SelectedValuePath= "Value";
    }

Теперь пользователь будет выбирать из списка ваших удобных для пользователя Descriptions, но то, что они выберут, будет enumзначением, которое вы можете использовать в коде. Чтобы получить доступ к выбору пользователя в коде, comboBoxUserReadable.SelectedItemбудет ComboEnumItemи comboBoxUserReadable.SelectedValueбудет EMyEnum.

Билл Паско
источник
1

Вы можете использовать универсальный тип:

public class ComboBoxItem<T>
{
    private string Text { get; set; }
    public T Value { get; set; }

    public override string ToString()
    {
        return Text;
    }

    public ComboBoxItem(string text, T value)
    {
        Text = text;
        Value = value;
    }
}

Пример использования простого типа int:

private void Fill(ComboBox comboBox)
    {
        comboBox.Items.Clear();
        object[] list =
            {
                new ComboBoxItem<int>("Architekt", 1),
                new ComboBoxItem<int>("Bauträger", 2),
                new ComboBoxItem<int>("Fachbetrieb/Installateur", 3),
                new ComboBoxItem<int>("GC-Haus", 5),
                new ComboBoxItem<int>("Ingenieur-/Planungsbüro", 9),
                new ComboBoxItem<int>("Wowi", 17),
                new ComboBoxItem<int>("Endverbraucher", 19)
            };

        comboBox.Items.AddRange(list);
    }
Ян Штекер
источник
0

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

Это код:

public Form1()
{
    eventos = cliente.GetEventsTypes(usuario);

    foreach (EventNo no in eventos)
    {
        cboEventos.Items.Add(no.eventno.ToString() + "--" +no.description.ToString());
        cboEventos2.Items.Add(no.eventno.ToString());
    }
}

private void lista_SelectedIndexChanged(object sender, EventArgs e)
{
    lista2.Items.Add(lista.SelectedItem.ToString());
}

private void cboEventos_SelectedIndexChanged(object sender, EventArgs e)
{
    cboEventos2.SelectedIndex = cboEventos.SelectedIndex;
}
Miguel
источник
0

Класс создания:

namespace WindowsFormsApplication1
{
    class select
    {
        public string Text { get; set; }
        public string Value { get; set; }
    }
}

Коды Form1:

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            List<select> sl = new List<select>();
            sl.Add(new select() { Text = "", Value = "" });
            sl.Add(new select() { Text = "AAA", Value = "aa" });
            sl.Add(new select() { Text = "BBB", Value = "bb" });
            comboBox1.DataSource = sl;
            comboBox1.DisplayMember = "Text";
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {

            select sl1 = comboBox1.SelectedItem as select;
            t1.Text = Convert.ToString(sl1.Value);

        }

    }
}
Безграничный Иса
источник
0

Вот как это делает Visual Studio 2013:

Один элемент:

comboBox1->Items->AddRange(gcnew cli::array< System::Object^  >(1) { L"Combo Item 1" });

Несколько предметов:

comboBox1->Items->AddRange(gcnew cli::array< System::Object^  >(3)
{
    L"Combo Item 1",
    L"Combo Item 2",
    L"Combo Item 3"
});

Нет необходимости делать переопределения класса или включать что-либо еще. А да то comboBox1->SelectedItemи comboBox1->SelectedIndexзвонки еще работают.

загадка
источник
0

Это похоже на некоторые другие ответы, но компактно и позволяет избежать преобразования в словарь, если у вас уже есть список.

Учитывая ComboBox"комбобокс" на форме окна и класс SomeClassсо stringсвойством типа Name,

List<SomeClass> list = new List<SomeClass>();

combobox.DisplayMember = "Name";
combobox.DataSource = list;

Это означает, что SelectedItem является SomeClassобъектом list, и каждый элемент comboboxбудет отображаться с использованием его имени.

Алекс Смит
источник
Правда! Я использовал DisplayMemberраньше ... Я всегда забываю, что это существует. Я привык к решению, которое нашел до того, как обратил внимание на это свойство, и оно не всегда поможет. Не все классы имеют Nameили Tagсвойство, или иметь свойство строки , которые можно было бы использовать произвольно в качестве отображаемого текста.
Матеус Роча,
Это хороший момент. Если вы можете изменить класс, то, возможно, стоит добавить такое свойство в класс, например, свойство 'ComboBoxText' (которое может возвращать метод ToString (), если он доступен). В качестве альтернативы, если класс не является изменяемым, возможно, будет возможно создать производный класс, в котором может быть реализовано свойство ComboBoxText. Это будет стоить того, если вам придется добавлять класс в ComboBox много раз. В противном случае проще использовать словарь, как описано в одном из других ответов.
Алекс Смит
Привет, Алекс, я ответил тем же методом, который обычно использую в этих случаях. Я думаю, это довольно близко к тому, что ты сказал, или, может быть, я не понял, что ты сказал. Я не наследовал класс, потому что некоторые классы могут требовать от вас реализации методов, которые мы не хотим переопределять (поэтому у нас будет куча методов с простым base.Method();), а также вам придется создать производный класс для каждого отдельного типа вы хотите добавить в поля со списком или списки. Класс, который я сделал, гибкий, вы можете использовать его с любым типом без лишних усилий. Посмотрите мой ответ ниже и скажите, что вы думаете :)
Матеус Роча,
Я согласен, ваш ответ определенно кажется более удобным, чем создание производного класса для каждого типа, который вы хотите добавить в комбинированный список. Хорошая работа! Я думаю, что в будущем, если у меня не будет такого свойства, как «Имя», я буду использовать что-то вроде вашего ответа или словарного ответа :)
Алекс Смит
0

Это очень простое решение для оконных форм, если все, что нужно, это конечное значение в виде (строки). Имена элементов будут отображаться в поле со списком, и выбранное значение можно будет легко сравнить.

List<string> items = new List<string>();

// populate list with test strings
for (int i = 0; i < 100; i++)
            items.Add(i.ToString());

// set data source
testComboBox.DataSource = items;

и на обработчике события получить значение (строку) выбранного значения

string test = testComboBox.SelectedValue.ToString();
Эстебан Вербель
источник
0

Лучшее решение здесь;

Dictionary<int, string> userListDictionary = new Dictionary<int, string>();
        foreach (var user in users)
        {
            userListDictionary.Add(user.Id,user.Name);
        }

        cmbUser.DataSource = new BindingSource(userListDictionary, null);
        cmbUser.DisplayMember = "Value";
        cmbUser.ValueMember = "Key";

Восстановить данные

MessageBox.Show(cmbUser.SelectedValue.ToString());
Орхан Байрам
источник
Несмотря на то, что я смог заполнить поле со списком, нажатие на него приводит к этой ошибке в VS2019. Был сделан вызов QueryInterface, запрашивающий интерфейс класса видимого управляемого COM-класса ComboBoxUiaProvider
MC9000