ComboBox: aggiunta di testo e valore a un elemento (nessuna fonte di legame)


202

In C # WinApp, come posso aggiungere sia testo che valore agli elementi del mio ComboBox? Ho fatto una ricerca e di solito le risposte usano "Binding to a source" .. ma nel mio caso non ho una fonte di binding pronta nel mio programma ... Come posso fare qualcosa del genere:

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

Risposte:


361

È necessario creare il proprio tipo di classe e sovrascrivere il metodo ToString () per restituire il testo desiderato. Ecco un semplice esempio di una classe che puoi usare:

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

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

Di seguito è riportato un semplice esempio del suo utilizzo:

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
abbiamo davvero bisogno di questa nuova classe ComboboxItem? penso che ne esiste già uno chiamato ListItem.
Amr Elgarhy,

15
Credo che possa essere disponibile solo in ASP.NET e non in WinForms.
Adam Markowitz,

1
No. L'articolo è un tipo separato che viene utilizzato solo per la memorizzazione dei dati degli articoli (testo, valore, riferimenti ad altri oggetti, ecc.). Non è un discendente di un ComboBox e sarebbe estremamente raro che lo fosse.
Adam Markowitz,

1
So di essere un po 'in ritardo con la festa, ma il modo in cui l'ho fatto in un ambiente Windows è stato quello di impostare un datatable, aggiungere elementi ad esso e associare la casella combinata al datatable. Si potrebbe pensare che ci dovrebbe essere un modo più pulito di farlo, ma non ne ho trovato uno (DisplayMember è la proprietà sulla casella combinata che si desidera che appaia il testo, ValueMember per il valore dei dati)
user2366842

4
come possiamo ottenere "SelectedValue" o selezionare la voce in base al valore ... Rispondetemi
Alpha Gabriel V. Tibol

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
Funziona perfettamente e questa dovrebbe essere la risposta selezionata. Ma non possiamo usare comboBox1.SelectedText invece di trasmettere .SelectedItem e prendere .Value?
Jeffrey Goines,

@fab come trovi l'oggetto nella casella combinata con una determinata chiave
Smith,

È possibile selezionare un elemento nella casella combinata in base alla chiave del dizionario? come selezionare il tasto 3, quindi verrà selezionato l'oggetto con il tasto 3.
Dror,

Questo metodo non funziona più per vs2015. Eccezioni sollevate sul fatto di non essere in grado di legare a nuovo displaymember e Valuemember
Plater

119

Puoi usare una classe anonima come questa:

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

AGGIORNAMENTO: Anche se il codice sopra verrà visualizzato correttamente nella casella combinata, non sarà possibile utilizzare SelectedValueo le SelectedTextproprietà di ComboBox. Per poterli usare, associa la casella combinata come di seguito:

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;

14
Vorrei modificarlo leggermente perché è probabile che un programmatore abbia bisogno di un ciclo for insieme a questo. Invece di un array ho usato un elenco List<Object> items = new List<Object>(); Poi sono stato in grado di utilizzare il metodo items.Add( new { Text = "report A", Value = "reportA" } );all'interno del ciclo.
Andrew,

1
Andrew, hai fatto in modo che List <Object> funzioni con la proprietà SelectedValue?
Peter PitLock,

@Venkat,comboBox.SelectedItem.GetType().GetProperty("Value").GetValue(comboBox.SelectedItem, null)
Optavius

2
@Venkat se usi la seconda soluzione che imposta il DataSourcepuoi usare le proprietà SelectedValueo SelectedTextdella casella combinata, quindi non c'è bisogno di fare alcun casting speciale.
JPProgrammer

32

È necessario utilizzare l' dynamicoggetto per risolvere l'elemento della casella combinata in fase di esecuzione.

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

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

(comboBox.SelectedItem as dynamic).Value

1
È molto meglio che creare una classe separata e sovrascrivere ToString ().
Don Shrout,

1
dynamic è disponibile solo in C # 4 e versioni successive. (.NET 4.5 credo)
MickeyfAgain_BeforeExitOfSO

Semplice e veloce da scrivere! L'ho fatto per SelectedValue in VB.net: Dim Value As String = CType (Me.SectionIDToComboBox.SelectedItem, Object) .Value
Hannington Mambo

1
In che modo, quindi, impostare la casella combinata corretta utilizzando "Valore"?
Dave Ludwig,

17

Puoi usare DictionaryObject invece di creare una classe personalizzata per aggiungere testo e valore in a Combobox.

Aggiungi chiavi e valori in un Dictionaryoggetto:

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

Associa l'oggetto Dizionario di origine a Combobox:

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

Recupera chiave e valore:

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

Fonte completa: Combobox Text nd Value


14

Questo è uno dei modi che mi sono appena venuti in mente:

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

E per modificare il testo o il valore di un elemento, puoi farlo in questo modo:

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

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

Non esiste una classe chiamata ListItem in Windows Form . Esiste solo in ASP.NET , quindi dovrai scrivere la tua classe prima di usarla, come ha fatto @Adam Markowitz nella sua risposta .

Controlla anche queste pagine, possono aiutare:


2
A meno che non mi sbagli, ListItem è disponibile solo in ASP.NET
Adam Markowitz,

si :( purtroppo è solo in ASP.net ... quindi cosa posso fare ora?
Bohn,

Quindi qual è il punto delle proprietà SelectedValue o SelectedText in una casella combinata?
JSON,

11

Non so se questo funzionerà per la situazione indicata nel post originale (non importa il fatto che sia due anni dopo), ma questo esempio funziona per 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";

Per leggere nuovamente il tuo valore, dovrai eseguire il cast della proprietà SelectedItem su un oggetto DictionaryEntry e quindi puoi valutare le proprietà Key e Value di quello. Per esempio:

DictionaryEntry deImgType = (DictionaryEntry)cmbImageType.SelectedItem;
MessageBox.Show(deImgType.Key + ": " + deImgType.Value);

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

Se qualcuno è ancora interessato a questo, ecco una classe semplice e flessibile per un oggetto combobox con un testo e un valore di qualsiasi tipo (molto simile all'esempio di 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;
    }
}

Usare il <T>è meglio che dichiarare il valuecome object, perché con objectallora dovresti tenere traccia del tipo che hai usato per ogni elemento e lanciarlo nel tuo codice per usarlo correttamente.

Lo sto usando nei miei progetti da un po 'di tempo ormai. È davvero utile.


4

Mi è piaciuta la risposta di fab ma non volevo usare un dizionario per la mia situazione, quindi ho sostituito un elenco di tuple.

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

Un esempio con 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

È possibile utilizzare questo codice per inserire alcuni elementi in una casella combinata con testo e valore.

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

Per favore, spiega la tua soluzione.
Vaibhav Bajaj,

Semplicemente, aggiungi i seguenti paesi nei rispettivi indici in una casella. Quando lo esegui. Un combox appaiono con un'opzione che è a 0 index.If si fa clic sul COMBOX l'altra opzione seguito vi mostrerà
Muhammad Ahmad

questo non funziona per id questo è semplicemente un modo per indicizzare l'elenco, non è di questo che si trattava
Mr Heelis,

2

Oltre alla risposta di Adam Markowitz, ecco un modo generico di (relativamente) semplicemente impostare i ItemSourcevalori di una casella combinata da enumsmostrare, mostrando allo stesso tempo l'attributo 'Descrizione'. (Penseresti che tutti vorrebbero farlo in modo che sarebbe un liner .NET , ma non lo è, e questo è il modo più elegante che ho trovato).

Innanzitutto, crea questa semplice classe per convertire qualsiasi valore Enum in 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;
    }
}

In secondo luogo, nel OnLoadgestore dell'evento, devi impostare l'origine della casella combinata in modo che sia un elenco di ComboEnumItemstutti i tipi Enumnel tuo Enumtipo. Ciò può essere ottenuto con Linq. Quindi imposta semplicemente 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";
    }

Ora l'utente selezionerà da un elenco di user friendly Descriptions, ma ciò che selezioneranno sarà il enumvalore che puoi usare nel codice. Per accedere alla selezione dell'utente nel codice, comboBoxUserReadable.SelectedItemsarà il ComboEnumIteme comboBoxUserReadable.SelectedValuesarà il EMyEnum.


1

È possibile utilizzare un tipo generico:

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

Esempio di utilizzo di un int-Type semplice:

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

Ho avuto lo stesso problema, quello che ho fatto è stato aggiungere un nuovo ComboBox con solo il valore nello stesso indice quindi il primo, e poi quando cambio la combo principale l'indice nel secondo cambia contemporaneamente, quindi prendo il valore del secondo combo e usalo.

Questo è il codice:

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

Creatore di classe:

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

Codici 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

Ecco come funziona Visual Studio 2013:

Articolo singolo:

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

Articoli multipli:

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

Non è necessario eseguire sostituzioni di classe o includere altro. E sì, le chiamate comboBox1->SelectedIteme comboBox1->SelectedIndexfunzionano ancora.


0

Questo è simile ad alcune delle altre risposte, ma è compatto ed evita la conversione in dizionario se hai già un elenco.

Data una ComboBox"casella combinata" su un modulo di Windows e una classe SomeClasscon la stringproprietà type Name,

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

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

Ciò significa che SelectedItem è un SomeClassoggetto da liste ogni elemento in comboboxverrà visualizzato usando il suo nome.


Vero! Ho usato DisplayMemberprima ... dimentico sempre che esiste. Mi sono abituato alla soluzione che ho trovato prima di prestare attenzione a questa proprietà, inoltre non sempre aiuterà. Non tutte le classi hanno una proprietà Nameo Tagoppure hanno una proprietà stringa che può essere utilizzata arbitrariamente come testo di visualizzazione.
Matheus Rocha,

Questo è un buon punto. Se è possibile modificare la classe, potrebbe valere la pena aggiungere tale proprietà alla classe, ad esempio una proprietà 'ComboBoxText' (che potrebbe restituire il metodo ToString () se disponibile). In alternativa, se la classe non è modificabile, potrebbe essere possibile creare una classe derivata in cui potrebbe essere implementata la proprietà 'ComboBoxText'. Ne varrebbe la pena se devi aggiungere la classe a un ComboBox più volte. Altrimenti, è più semplice usare un dizionario come spiegato in una delle altre risposte.
Alex Smith,

Ehi Alex, ho fatto una risposta con l'etere che di solito uso in questi casi. Penso che sia abbastanza vicino a quello che hai detto o forse non ho capito cosa hai detto. Non sono derivato dalla classe perché alcune classi potrebbero richiedere di implementare metodi che non vogliamo sovrascrivere (quindi avremmo un mucchio di metodi con un semplice base.Method();), inoltre dovresti creare una classe derivata per ogni tipo diverso che si desidera aggiungere a caselle combinate o caselle di riepilogo. La classe che ho creato è flessibile, puoi usarla con qualsiasi tipo senza sforzo extra. Guarda sotto per la mia risposta e dimmi cosa ne pensi :)
Matheus Rocha,

Sono d'accordo, la tua risposta sembra decisamente più conveniente della creazione di una classe derivata per ogni tipo che desideri aggiungere a una casella combinata. Bel lavoro! Penso che in futuro se non avrò prontamente disponibile una proprietà come "Nome", userò qualcosa come la tua risposta o la risposta del dizionario :)
Alex Smith,

0

Questa è una soluzione molto semplice per i moduli di Windows se tutto ciò che serve è il valore finale come (stringa). I nomi degli elementi verranno visualizzati nella casella combinata e il valore selezionato può essere facilmente confrontato.

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;

e sul gestore eventi ottenere il valore (stringa) del valore selezionato

string test = testComboBox.SelectedValue.ToString();

0

Soluzione migliore qui;

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

Recupera dati

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

Mentre sono stato in grado di riempire la casella combinata, facendo clic su di essa si ottiene questo errore in VS2019 È stata effettuata una chiamata QueryInterface che richiede l'interfaccia della classe della classe gestita visibile COM 'ComboBoxUiaProvider
MC9000
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.