ComboBox: Agregar texto y valor a un elemento (sin fuente de enlace)

202

En C # WinApp, ¿cómo puedo agregar texto y valor a los elementos de mi ComboBox? Hice una búsqueda y, por lo general, las respuestas usan "Enlace a una fuente" ... pero en mi caso no tengo una fuente de enlace lista en mi programa ... ¿Cómo puedo hacer algo como esto?

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

Respuestas:

361

Debe crear su propio tipo de clase y anular el método ToString () para devolver el texto que desea. Aquí hay un ejemplo simple de una clase que puede usar:

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

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

El siguiente es un ejemplo simple de su uso:

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());
}
Adam Markowitz
fuente
44
¿realmente necesitamos esta nueva clase ComboboxItem? Creo que ya existe uno llamado ListItem.
Amr Elgarhy
15
Creo que solo puede estar disponible en ASP.NET y no en WinForms.
Adam Markowitz
1
No. El elemento es un tipo separado que solo se usa para almacenar los datos de los elementos (texto, valor, referencias a otros objetos, etc.). No es un descendiente de un ComboBox y sería extremadamente raro que lo fuera.
Adam Markowitz
1
Sé que llego un poco tarde a la fiesta, pero cómo hice esto en un entorno de formulario de Windows puro fue configurar una tabla de datos, agregarle elementos y vincular el cuadro combinado a la tabla de datos. Uno podría pensar que debería haber una forma más limpia de hacerlo, pero no he encontrado una (DisplayMember es la propiedad en el cuadro combinado que desea que aparezca el texto, ValueMember para el valor de los datos)
user2366842
44
¿cómo obtenemos "SelectedValue" o seleccionamos el elemento en función del valor ... por favor responda
Alpha Gabriel V. Timbol
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;
fabuloso
fuente
2
Funciona perfecto y esta debería ser la respuesta seleccionada. ¿Pero no podemos usar comboBox1.SelectedText en lugar de lanzar .SelectedItem y tomar .Value?
Jeffrey Goines
@fab, ¿cómo encuentras el elemento en el cuadro combinado con una clave determinada
Smith
¿Es posible seleccionar un elemento en el cuadro combinado basado en la clave del diccionario? como seleccionar la Clave 3 para seleccionar el Elemento con la Clave 3.
Dror
Este método ya no funciona para vs2015. Excepciones lanzadas sobre no poder vincularse con un nuevo miembro de la pantalla y Valuemember
Plater
119

Puede usar una clase anónima como esta:

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

ACTUALIZACIÓN: Aunque el código anterior se mostrará correctamente en el cuadro combinado, no podrá usar SelectedValueni SelectedTextpropiedades de ComboBox. Para poder usarlos, vincule el cuadro combinado de la siguiente manera:

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
fuente
14
Me gustaría modificar esto ligeramente porque es probable que un programador necesite un bucle for junto con esto. En lugar de una matriz, utilicé una lista. List<Object> items = new List<Object>(); Luego pude usar el método items.Add( new { Text = "report A", Value = "reportA" } );dentro del ciclo.
Andrew
1
Andrew, ¿conseguiste que List <Object> funcione con la propiedad SelectedValue?
Peter PitLock
@Venkat,comboBox.SelectedItem.GetType().GetProperty("Value").GetValue(comboBox.SelectedItem, null)
Optavius
2
@Venkat si usa la segunda solución que establece DataSource, puede usar las propiedades SelectedValueo SelectedTextdel cuadro combinado, por lo que no es necesario realizar ninguna conversión especial.
JPProgrammer
32

Debe usar el dynamicobjeto para resolver el elemento del cuadro combinado en tiempo de ejecución.

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

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

(comboBox.SelectedItem as dynamic).Value
Mert Cingoz
fuente
1
Esto es mucho mejor que crear una clase separada y anular ToString ().
Don Shrout
1
dinámico solo está disponible en C # 4 y superior. (.NET 4.5 creo)
MickeyfAgain_BeforeExitOfSO
¡Simple y más rápido de escribir! Hice esto para SelectedValue en VB.net: Dim Value As String = CType (Me.SectionIDToComboBox.SelectedItem, Object) .Value
Hannington Mambo
1
¿Cómo, entonces, establecer el elemento de cuadro combinado correcto usando el "Valor"?
Dave Ludwig
17

Puede usar DictionaryObject en lugar de crear una clase personalizada para agregar texto y valor en a Combobox.

Agregar claves y valores en un Dictionaryobjeto:

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

Enlace el objeto del Diccionario fuente a Combobox:

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

Recuperar clave y valor:

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

Fuente completa: Combobox Text nd Value

cronynaval
fuente
14

Esta es una de las formas que me vino a la mente:

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

Y para cambiar el texto o el valor de un elemento, puede hacerlo así:

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

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

No hay una clase llamada ListItem en Windows Forms . Solo existe en ASP.NET , por lo que deberá escribir su propia clase antes de usarla, al igual que @Adam Markowitz hizo en su respuesta .

También revise estas páginas, pueden ayudar:

Amr Elgarhy
fuente
2
A menos que me equivoque, ListItem solo está disponible en ASP.NET
Adam Markowitz
sí :( desafortunadamente solo está en ASP.net ... entonces, ¿qué puedo hacer ahora?
Bohn
Entonces, ¿cuál es el punto de las propiedades SelectedValue o SelectedText en un cuadro combinado?
JSON
11

No sé si esto funcionará para la situación dada en la publicación original (no importa el hecho de que esto sea dos años después), pero este ejemplo funciona para mí:

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

Para volver a leer su valor, tendrá que convertir la propiedad SelectedItem en un objeto DictionaryEntry, y luego puede evaluar las propiedades Clave y Valor de eso. Por ejemplo:

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

Si alguien todavía está interesado en esto, aquí hay una clase simple y flexible para un elemento de cuadro combinado con un texto y un valor de cualquier tipo (muy similar al ejemplo de Adam Markowitz):

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

Usar el <T>es mejor que declarar el valuecomo un object, porque conobject eso tendrías que hacer un seguimiento del tipo que usaste para cada elemento y lanzarlo en tu código para usarlo correctamente.

Lo he estado usando en mis proyectos desde hace bastante tiempo. Es realmente útil.

Matheus Rocha
fuente
4

Me gustó la respuesta de Fab, pero no quería usar un diccionario para mi situación, así que sustituí una lista de tuplas.

// 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;
Maggie
fuente
3

Un ejemplo usando 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
fuente
3

Puede usar este código para insertar algunos elementos en un cuadro combinado con texto y valor.

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"/>
Muhammad Ahmad
fuente
Por favor explique su solución.
Vaibhav Bajaj
Simplemente, agregue los siguientes países en sus respectivos índices en un cuadro combinado. Cuando lo ejecute. Aparece un cuadro combinado con una opción que está en el índice 0. Si hace clic en el cuadro combinado, aparecerá la siguiente opción
Muhammad Ahmad
esto no funciona para las identificaciones, esta es simplemente una forma de indexar la lista, esa no es la cuestión
Sr. Heelis el
2

Además de la respuesta de Adam Markowitz, aquí hay una forma de propósito general de (relativamente) simplemente establecer los ItemSourcevalores de un cuadro combinado enums, mientras se muestra el atributo 'Descripción' al usuario. (Uno pensaría que todos querrían hacer esto para que sea un .NET one liner, pero simplemente no lo es, y esta es la forma más elegante que he encontrado).

Primero, cree esta clase simple para convertir cualquier valor de Enum en un elemento 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;
    }
}

En segundo lugar, en el OnLoadcontrolador de eventos, es necesario establecer el origen de su cuadro combinado a ser una lista de ComboEnumItemsbase en todos los Enumde su Enumtipo. Esto se puede lograr con Linq. Luego solo configura 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";
    }

Ahora el usuario seleccionará de una lista de sus usuarios amigables Descriptions, pero lo que seleccionarán será el enumvalor que puede usar en el código. Para acceder a la selección del usuario en el código, comboBoxUserReadable.SelectedItemserá el ComboEnumItemy comboBoxUserReadable.SelectedValueserá el EMyEnum.

Bill Pascoe
fuente
1

Puede usar un tipo genérico:

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

Ejemplo de uso de un tipo int simple:

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);
    }
Jan Staecker
fuente
0

Tuve el mismo problema, lo que hice fue agregar un nuevo ComboBox con solo el valor en el mismo índice, luego el primero, y luego, cuando cambio el combo principal, el índice en el segundo cambia al mismo tiempo, luego tomo el valor del segundo combo y úsalo.

Este es el código:

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
fuente
0

Clase creat:

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

Códigos 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);

        }

    }
}
Isa ilimitado
fuente
0

Así es como lo hace Visual Studio 2013:

Objeto unico:

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

Artículos múltiples:

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

No es necesario anular la clase ni incluir nada más. Y sí, las llamadas comboBox1->SelectedItemy comboBox1->SelectedIndextodavía funcionan.

Enigma
fuente
0

Esto es similar a algunas de las otras respuestas, pero es compacto y evita la conversión al diccionario si ya tiene una lista.

Dado un ComboBox"cuadro combinado" en un formulario de Windows y una clase SomeClasscon la stringpropiedad type Name,

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

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

Lo que significa que SelectedItem es un SomeClassobjeto listy cada elemento comboboxse mostrará con su nombre.

Alex Smith
fuente
¡Cierto! Lo he usado DisplayMemberantes ... Siempre olvido que existe. Me acostumbré a la solución que encontré antes de prestar atención a esta propiedad, además, no siempre ayudará. No todas las clases tienen una propiedad Nameo Tag, o tienen una propiedad de cadena que podría usarse arbitrariamente como texto de visualización.
Matheus Rocha
Este es un buen punto. Si puede modificar la clase, podría valer la pena agregar dicha propiedad a la clase, por ejemplo, una propiedad 'ComboBoxText' (que podría devolver el método ToString () si está disponible). Alternativamente, si la clase no es modificable, podría ser posible crear una clase derivada en la que se podría implementar la propiedad 'ComboBoxText'. Esto solo valdría la pena si tiene que agregar la clase a un ComboBox muchas veces. De lo contrario, es más simple usar un diccionario como se explica en una de las otras respuestas.
Alex Smith
Hola Alex, he respondido con el método que suelo usar en estos casos. Creo que está bastante cerca de lo que dijiste o tal vez no entendí lo que dijiste. No derivaba de la clase porque algunas clases podrían requerir que implementes métodos que no queremos anular (por lo que tendríamos un montón de métodos con un simple base.Method();), también tendrías que crear una clase derivada para cada tipo diferente que desee agregar a cuadros combinados o cuadros de lista. La clase que hice es flexible, puedes usarla con cualquier tipo sin esfuerzo adicional. Mira a continuación mi respuesta y dime lo que piensas :)
Matheus Rocha
Estoy de acuerdo, su respuesta definitivamente parece más conveniente que crear una clase derivada para cada tipo que desee agregar a un cuadro combinado. ¡Buen trabajo! Creo que en el futuro si no tengo una propiedad como 'Nombre' disponible, voy a usar algo como su respuesta o la respuesta del diccionario :)
Alex Smith
0

Esta es una solución muy simple para formularios de Windows si todo lo que se necesita es el valor final como una (cadena). Los nombres de los elementos se mostrarán en el cuadro combinado y el valor seleccionado se puede comparar fácilmente.

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;

y en el controlador de eventos obtener el valor (cadena) del valor seleccionado

string test = testComboBox.SelectedValue.ToString();
Esteban Verbel
fuente
0

Mejor solución aquí;

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

Recuperar datos

MessageBox.Show(cmbUser.SelectedValue.ToString());
Orhan Bayram
fuente
Si bien pude llenar el cuadro combinado, al hacer clic en él aparece este error en VS2019 Se realizó una llamada a QueryInterface solicitando la interfaz de clase de la clase administrada COM visible 'ComboBoxUiaProvider
MC9000