ComboBox: adicionando texto e valor a um item (sem fonte de ligação)

202

No C # WinApp, como posso adicionar texto e valor aos itens da minha ComboBox? Eu fiz uma pesquisa e geralmente as respostas estão usando "Vinculação a uma fonte" .. mas no meu caso eu não tenho uma fonte vinculativa pronta no meu programa ... Como posso fazer algo assim:

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

Respostas:

361

Você deve criar seu próprio tipo de classe e substituir o método ToString () para retornar o texto desejado. Aqui está um exemplo simples de uma classe que você pode usar:

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

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

A seguir, é apresentado um exemplo simples de seu 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
fonte
4
precisamos mesmo dessa nova classe ComboboxItem? Eu acho que já existe um chamado ListItem.
Amr Elgarhy
15
Eu acredito que pode estar disponível apenas no ASP.NET e não no WinForms.
Adam Markowitz
1
Não. O item é um tipo separado que é usado apenas para armazenar os dados dos itens (texto, valor, referências a outros objetos, etc.). Não é um descendente de um ComboBox e seria extremamente raro que seria.
Adam Markowitz
1
Sei que estou um pouco atrasado para a festa, mas como fiz isso em um ambiente de formulário do Windows puro foi configurar uma tabela de dados, adicionar itens a ela e vincular a caixa de combinação à tabela de dados. Alguém poderia pensar que deve haver uma maneira mais limpa de fazer isso, mas eu não encontrei um (DisplayMember é propriedade na combobox você quer para o texto que aparece, ValueMember para o valor dos dados)
user2366842
4
como obtemos "SelectedValue" ou selecionamos o item com base no 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
fonte
2
Funciona perfeitamente e esta deve ser a resposta selecionada. Mas não podemos usar comboBox1.SelectedText em vez de converter .SelectedItem e pegar .Value?
Jeffrey Goines
@fab como você encontrar item na caixa de combinação com uma determinada tecla
Smith
É possível selecionar um item na caixa de combinação com base na chave do dicionário? como selecione a Chave 3, para que o Item com a Chave 3 seja selecionado.
Dror
Este método não funciona mais para o vs2015. Exceções jogado sobre não ser capaz de se ligar a nova DisplayMember e ValueMember
Plater
119

Você pode usar classe 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" });

ATUALIZAÇÃO: Embora o código acima seja exibido corretamente na caixa de combinação, você não poderá usar SelectedValuenem as SelectedTextpropriedades de ComboBox. Para poder usá-los, vincule a caixa de combinação como abaixo:

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
fonte
14
Eu gostaria de modificar isso um pouco porque é provável que um programador precise de um loop for junto com isso. Em vez de uma matriz, usei uma lista. List<Object> items = new List<Object>(); Em seguida, pude usar o método items.Add( new { Text = "report A", Value = "reportA" } );dentro do loop.
25415 Andrew
1
Andrew, você conseguiu que a List <Object> funcionasse com a propriedade SelectedValue?
Peter PitLock
@Venkat,comboBox.SelectedItem.GetType().GetProperty("Value").GetValue(comboBox.SelectedItem, null)
Optavius
2
@Venkat, se você usar a segunda solução que define o valor, DataSourcepode usar as propriedades SelectedValueou SelectedTextda caixa de combinação, portanto, não é necessário fazer nenhuma conversão especial.
JPProgrammer
32

Você deve usar o dynamicobjeto para resolver o item da caixa de combinação em tempo de execução.

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

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

(comboBox.SelectedItem as dynamic).Value
Mert Cingoz
fonte
1
Isso é muito melhor do que criar uma classe separada e substituir ToString ().
Don Shrout
1
dinâmica está disponível apenas em C # 4 e superior. (.NET 4.5, eu acho) #
7788 MickeyfAgain_BeforeExitOfSO
Simples e rápido de escrever! Eu fiz isso por SelectedValue em VB.net: Dim Valor As String = CType (Me.SectionIDToComboBox.SelectedItem, Object) .Value
Hannington Mambo
1
Como então, para definir o item correto da caixa de combinação usando o "Valor"?
Dave Ludwig
17

Você pode usar o DictionaryObject em vez de criar uma classe personalizada para adicionar texto e valor em a Combobox.

Adicione chaves e valores em um Dictionaryobjeto:

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

Vincule o objeto Dicionário de origem a Combobox:

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

Recuperar chave e valor:

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

Fonte completa: Combobox Text nd Value

cronynaval
fonte
14

Essa é uma das maneiras que me veio à mente:

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

E para alterar o texto ou o valor de um item, você pode fazer o seguinte:

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

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

Não há nenhuma classe chamada ListItem no Windows Forms . Ele existe apenas no ASP.NET , portanto, você precisará escrever sua própria classe antes de usá-la, da mesma forma que @Adam Markowitz em sua resposta .

Verifique também estas páginas, elas podem ajudar:

Amr Elgarhy
fonte
2
Se não me engano, ListItem só está disponível em ASP.NET
Adam Markowitz
sim :( infelizmente, é apenas em ASP.net ... então o que posso fazer agora?
Bohn
Então, qual é o ponto das propriedades SelectedValue ou SelectedText em uma caixa de combinação?
JSON
11

Não sei se isso funcionará para a situação apresentada na postagem original (não importa o fato de que isso acontece dois anos depois), mas este exemplo funciona para mim:

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 ler seu valor novamente, você precisará converter a propriedade SelectedItem em um objeto DictionaryEntry e, em seguida, avaliar as propriedades Key e Value desse. Por exemplo:

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

Se alguém ainda estiver interessado nisso, aqui está uma classe simples e flexível para um item da caixa de combinação com um texto e um valor de qualquer tipo (muito semelhante ao exemplo 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 o <T>é melhor do que declarar valuecomo um object, porque comobject ele é necessário acompanhar o tipo usado para cada item e convertê-lo em seu código para usá-lo corretamente.

Eu tenho usado em meus projetos há um bom tempo agora. É realmente útil.

Matheus Rocha
fonte
4

Eu gostei da resposta de fab, mas não queria usar um dicionário para a minha situação, então substituí uma 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
fonte
3

Um exemplo 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
fonte
3

Você pode usar esse código para inserir alguns itens em uma caixa de combinação com texto e 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
fonte
Por favor, explique sua solução.
Vaibhav Bajaj
Simplesmente, adicione os seguintes países em seus respectivos índices em um combox. Quando você o executa. A combox aparecer com uma opção que está em 0 index.If clicar no combox a outra opção seguinte irá mostrar
Muhammad Ahmad
isso não trabalho para id é esta é simplesmente uma forma de índice de lista, não é isso que a pergunta foi sobre
Sr. Heelis
2

Além da resposta de Adam Markowitz, eis uma maneira geral de (relativamente) simplesmente definir o ItemSource valores de uma caixa de combinação enums, mostrando o atributo 'Descrição' para o usuário. (Você acha que todo mundo gostaria de fazer isso para que fosse um .NET um liner do , mas não é, e é a maneira mais elegante que eu encontrei).

Primeiro, crie esta classe simples para converter qualquer valor Enum em um item 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;
    }
}

Em segundo lugar no seu OnLoadmanipulador de eventos, você precisa definir a fonte de sua caixa de combinação para ser uma lista de ComboEnumItemsbase em toda Enuma sua Enumtipo. Isso pode ser alcançado com o Linq. Em seguida, basta definir o 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";
    }

Agora, o usuário selecionará de uma lista amigável Descriptions, mas o que selecionar será o enumvalor que você pode usar no código. Para acessar a seleção do usuário no código, comboBoxUserReadable.SelectedItemserá o ComboEnumIteme comboBoxUserReadable.SelectedValueserá o EMyEnum.

Bill Pascoe
fonte
1

Você pode usar um 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;
    }
}

Exemplo de uso de um simples tipo 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);
    }
Jan Staecker
fonte
0

Eu tive o mesmo problema, o que fiz foi adicionar um novo ComboBox com apenas o valor no mesmo índice do que o primeiro e, em seguida, quando altero o combo principal, o índice no segundo altera ao mesmo tempo, então pego o valor do segundo combo e use-o.

Este é o 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
fonte
0

Creat da classe:

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

Códigos do Formulário1:

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 sem limites
fonte
0

É assim que o Visual Studio 2013 faz isso:

Item único:

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

Vários itens:

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

Não há necessidade de fazer substituições de classe ou incluir qualquer outra coisa. E sim, as chamadas comboBox1->SelectedIteme comboBox1->SelectedIndexainda funcionam.

Enigma
fonte
0

Isso é semelhante a algumas das outras respostas, mas é compacto e evita a conversão para dicionário, se você já possui uma lista.

Dado um ComboBox"combobox" em um formulário janelas e uma classe SomeClasscom a stringpropriedade de tipo Name,

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

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

O que significa que o SelectedItem é um SomeClassobjeto liste cada item comboboxserá exibido usando seu nome.

Alex Smith
fonte
Verdade! Eu já usei DisplayMemberantes ... sempre esqueço que existe. Eu me acostumei com a solução que encontrei antes de prestar atenção a essa propriedade, também nem sempre ajuda. Nem todas as classes possuem uma propriedade Nameou Tag, ou possuem uma propriedade de cadeia que pode ser usada arbitrariamente como um texto de exibição.
Matheus Rocha
Este é um bom argumento. Se você pode modificar a classe, pode valer a pena adicionar essa propriedade à classe, por exemplo, uma propriedade 'ComboBoxText' (que pode retornar o método ToString (), se disponível). Como alternativa, se a classe não for modificável, poderá ser possível criar uma classe derivada na qual a propriedade 'ComboBoxText' possa ser implementada. Isso só valeria a pena se você tiver que adicionar a classe a uma ComboBox várias vezes. Caso contrário, é mais simples usar apenas um dicionário, conforme explicado em uma das outras respostas.
Alex Smith
Ei, Alex, eu respondi com o método que costumo usar nesses casos. Eu acho que é bem parecido com o que você disse ou talvez eu não tenha entendido o que você disse. Eu não derivei da classe porque algumas classes podem exigir que você implemente métodos que não queremos substituir (portanto, teríamos vários métodos com um simples base.Method();), mas você também precisaria criar uma classe derivada para cada tipo diferente que você deseja adicionar às caixas de combinação ou caixas de listagem. A classe que fiz é flexível, você pode usar com qualquer tipo sem nenhum esforço extra. Veja abaixo a minha resposta, e me diga o que você pensa :)
Matheus Rocha
Concordo que sua resposta definitivamente parece mais conveniente do que criar uma classe derivada para cada tipo que você deseja adicionar a uma caixa de combinação. Bom trabalho! Eu acho que no futuro, se eu não tenho uma propriedade como 'Nome' prontamente disponível Vou usar algo como a sua resposta ou a resposta dicionário :)
Alex Smith
0

Esta é uma solução muito simples para formulários do Windows, se tudo o que for necessário for o valor final como (string). Os nomes dos itens serão exibidos na caixa de combinação e o valor selecionado pode ser facilmente comparado.

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 no manipulador de eventos, obtenha o valor (string) do valor selecionado

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

Melhor solução aqui;

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 dados

MessageBox.Show(cmbUser.SelectedValue.ToString());
Orhan Bayram
fonte
Enquanto eu era capaz de preencher a caixa de combinação, clicar nela produz esse erro no VS2019 Foi feita uma chamada QueryInterface solicitando a interface de classe da classe gerenciada visível COM 'ComboBoxUiaProvider
MC9000