213
votes

In C# WinApp, how can I add both Text and Value to the items of my ComboBox? I did a search and usually the answers are using "Binding to a source".. but in my case I do not have a binding source ready in my program... How can I do something like this:

combo1.Item[1] = "DisplayText";
combo1.Item[1].Value = "useful Value"
20

20 Answers

388
votes

You must create your own class type and override the ToString() method to return the text you want. Here is a simple example of a class you can use:

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

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

The following is a simple example of its usage:

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());
}
198
votes
// 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;
128
votes

You can use anonymous class like this:

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

UPDATE: Although above code will properly display in combo box, you will not be able to use SelectedValue or SelectedText properties of ComboBox. To be able to use those, bind combo box as below:

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;
39
votes

You should use dynamic object to resolve combobox item in run-time.

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

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

(comboBox.SelectedItem as dynamic).Value
19
votes

You can use Dictionary Object instead of creating a custom class for adding text and value in a Combobox.

Add keys and values in a Dictionary Object:

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

Bind the source Dictionary object to Combobox:

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

Retrieve Key and value:

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

Full Source : Combobox Text nd Value

15
votes

This is one of the ways that just came to mind:

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

And to change text of or value of an item, you can do it like this:

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

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

There is no class called ListItem in Windows Forms. It only exists in ASP.NET, so you will need to write your own class before using it, the same as @Adam Markowitz did in his answer.

Also check these pages, they may help:

11
votes

Don't know if this will work for the situation given in the original post (never mind the fact that this is two years later), but this example works for me:

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

To read your value back out, you'll have to cast the SelectedItem property to a DictionaryEntry object, and you can then evaluate the Key and Value properties of that. For instance:

DictionaryEntry deImgType = (DictionaryEntry)cmbImageType.SelectedItem;
MessageBox.Show(deImgType.Key + ": " + deImgType.Value);
7
votes
//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
votes

If anyone is still interested in this, here is a simple and flexible class for a combobox item with a text and a value of any type (very similar to Adam Markowitz's example):

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

Using the <T> is better than declaring the value as an object, because with object you'd then have to keep track of the type you used for each item, and cast it in your code to use it properly.

I've been using it on my projects for quite a while now. It is really handy.

4
votes

I liked fab's answer but didn't want to use a dictionary for my situation so I substituted a list of tuples.

// 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
votes

An example using 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();
3
votes

You can use this code to insert some items into a combo box with text and value.

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"/>
2
votes

You may use a generic Type:

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

Example of using a simple int-Type:

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);
    }
2
votes

Further to Adam Markowitz's answer, here is a general purpose way of (relatively) simply setting the ItemSource values of a combobox to be enums, while showing the 'Description' attribute to the user. (You'd think everyone would want to do this so that it would be a .NET one liner, but it just isn't, and this is the most elegant way I've found).

First, create this simple class for converting any Enum value into a ComboBox item:

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

Secondly in your OnLoad event handler, you need to set the source of your combo box to be a list of ComboEnumItems based on every Enum in your Enum type. This can be achieved with Linq. Then just set the 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";
    }

Now the user will select from a list of your user friendly Descriptions, but what they select will be the enum value which you can use in code. To access the user's selection in code, comboBoxUserReadable.SelectedItem will be the ComboEnumItem and comboBoxUserReadable.SelectedValue will be the EMyEnum.

1
votes

Class creat:

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

Form1 Codes:

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

        }

    }
}
1
votes

Better solution here;

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

Retreive Data

MessageBox.Show(cmbUser.SelectedValue.ToString());
0
votes

I had the same problem, what I did was add a new ComboBox with just the value in the same index then the first one, and then when I change the principal combo the index in the second one change at same time, then I take the value of the second combo and use it.

This is the code:

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

This is how Visual Studio 2013 does it:

Single item:

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

Multiple Items:

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

No need to do class overrides or include anything else. And yes the comboBox1->SelectedItem and comboBox1->SelectedIndex calls still work.

0
votes

This is similar to some of the other answers, but is compact and avoids the conversion to dictionary if you already have a list.

Given a ComboBox "combobox" on a windows form and a class SomeClass with the string type property Name,

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

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

Which means that the SelectedItem is a SomeClass object from list, and each item in combobox will be displayed using its name.

0
votes

This is a very simple solution for windows forms if all is needed is the final value as a (string). The items' names will be displayed on the Combo Box and the selected value can be easily compared.

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;

and on the event handler get the value (string) of the selected value

string test = testComboBox.SelectedValue.ToString();