ComboBox: Dodawanie tekstu i wartości do elementu (brak źródła wiązania)

202

W C # WinApp, jak mogę dodać zarówno tekst, jak i wartość do elementów mojego ComboBox? Przeprowadziłem wyszukiwanie i zwykle odpowiedzi używają „Powiązania ze źródłem” .. ale w moim przypadku nie mam gotowego źródła powiązania w moim programie ... Jak mogę zrobić coś takiego:

combo1.Item[1] = "DisplayText";
combo1.Item[1].Value = "useful Value"
Bohn
źródło

Odpowiedzi:

361

Musisz utworzyć własny typ klasy i przesłonić metodę ToString (), aby zwrócić żądany tekst. Oto prosty przykład klasy, z której możesz skorzystać:

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

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

Oto prosty przykład użycia:

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
źródło
4
czy naprawdę potrzebujemy nowej klasy ComboboxItem? myślę, że istnieje już jeden o nazwie ListItem.
Amr Elgarhy,
15
Wierzę, że może być dostępny tylko w ASP.NET, a nie WinForm.
Adam Markowitz,
1
Nie. Przedmiot jest osobnym typem, który służy wyłącznie do przechowywania danych przedmiotów (tekst, wartość, odniesienia do innych obiektów itp.). To nie jest potomek ComboBoxa i byłoby to niezwykle rzadkie.
Adam Markowitz,
1
Wiem, że jestem nieco spóźniony na imprezę, ale to, jak to zrobiłem w czystym środowisku okienkowym, polegało na skonfigurowaniu bazy danych, dodaniu do niej elementów i powiązaniu comboboxu z bazą danych. Można by pomyśleć, że powinien istnieć czystszy sposób na zrobienie tego, ale nie znalazłem takiego (DisplayMember to właściwość w polu tekstowym, w którym chcesz wyświetlać tekst, ValueMember dla wartości danych)
user2366842
4
jak uzyskać „SelectedValue” lub wybrać pozycję na podstawie wartości ... odpowiedz
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;
fab
źródło
2
Działa idealnie i to powinna być wybrana odpowiedź. Ale czy nie możemy użyć comboBox1.SelectedText zamiast rzutowania .SelectedItem i pobrania .Value?
Jeffrey Goines
@ fab jak znaleźć przedmiot w comboboxie z pewnym kluczem
Smith
Czy można wybrać element w comboboxie na podstawie klucza słownika? jak wybierz klucz 3, więc element z kluczem 3 zostanie wybrany.
Dror
Ta metoda nie działa już dla vs2015. Zgłoszono wyjątki dotyczące niemożności związania się z nowym członkiem wiadomości i Valuemember
Plater,
119

Możesz użyć anonimowej klasy w następujący sposób:

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

AKTUALIZACJA: Chociaż powyższy kod będzie poprawnie wyświetlany w polu kombi, nie będziesz mógł używać SelectedValueani SelectedTextwłaściwości ComboBox. Aby móc z nich skorzystać, powiąż pole kombi, jak poniżej:

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
źródło
14
Chciałbym to nieco zmodyfikować, ponieważ programista prawdopodobnie będzie potrzebował pętli for wraz z tym. Zamiast tablicy użyłem listy. List<Object> items = new List<Object>(); Następnie mogłem użyć metody items.Add( new { Text = "report A", Value = "reportA" } );w pętli.
Andrew
1
Andrew, czy dostałeś List <Object> do pracy z właściwością SelectedValue?
Peter PitLock
@Venkat,comboBox.SelectedItem.GetType().GetProperty("Value").GetValue(comboBox.SelectedItem, null)
Optavius,
2
@Venkat, jeśli używasz drugiego rozwiązania, które ustawia DataSource, możesz użyć właściwości SelectedValuelub SelectedTextwłaściwości combobox, więc nie musisz wykonywać żadnych specjalnych rzutów.
JPProgrammer,
32

Należy użyć dynamicobiektu do rozwiązania elementu combobox w czasie wykonywania.

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

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

(comboBox.SelectedItem as dynamic).Value
Mert Cingoz
źródło
1
Jest to o wiele lepsze niż tworzenie osobnej klasy i zastępowanie ToString ().
Don Shrout
1
dynamiczny jest dostępny tylko w C # 4 i wyższych. (Myślę, że .NET 4.5)
MickeyfAgain_BeforeExitOfSO
Prosty i szybszy do napisania! Zrobiłem to dla SelectedValue w VB.net: Dim Value As String = CType (Me.SectionIDToComboBox.SelectedItem, Object) .Value
Hannington Mambo
1
Jak zatem ustawić prawidłowy element pola kombi przy użyciu „Wartości”?
Dave Ludwig
17

Możesz użyć DictionaryObject zamiast tworzyć niestandardową klasę do dodawania tekstu i wartości w Combobox.

Dodaj klucze i wartości w Dictionaryobiekcie:

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

Powiąż źródłowy obiekt Dictionary z Combobox:

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

Pobierz klucz i wartość:

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

Pełne źródło: Combobox Text nd Value

cronynaval
źródło
14

Oto jeden ze sposobów, który właśnie przyszedł mi do głowy:

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

Aby zmienić tekst lub wartość przedmiotu, możesz to zrobić w następujący sposób:

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

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

W formularzach Windows nie ma klasy o nazwie ListItem . Istnieje tylko w ASP.NET , więc przed użyciem musisz napisać własną klasę, tak samo jak @Adam Markowitz w swojej odpowiedzi .

Sprawdź również te strony, mogą one pomóc:

Amr Elgarhy
źródło
2
O ile się nie mylę, ListItem jest dostępny tylko w ASP.NET
Adam Markowitz
tak :( niestety jest tylko w ASP.net ... więc co mogę teraz zrobić?
Bohn
Jaki jest zatem sens właściwości SelectedValue lub SelectedText w combobox?
JSON
11

Nie wiem, czy to zadziała w sytuacji podanej w oryginalnym poście (nie wspominając o tym, że to dwa lata później), ale ten przykład działa dla mnie:

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

Aby ponownie odczytać wartość, musisz rzutować właściwość SelectedItem na obiekt DictionaryEntry, a następnie możesz ocenić jej właściwości Key i Value. Na przykład:

DictionaryEntry deImgType = (DictionaryEntry)cmbImageType.SelectedItem;
MessageBox.Show(deImgType.Key + ": " + deImgType.Value);
ChuckG
źródło
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
źródło
5

Jeśli ktoś nadal jest tym zainteresowany, oto prosta i elastyczna klasa dla elementu combobox z tekstem i wartością dowolnego typu (bardzo podobny do przykładu Adama Markowitza):

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

Używanie <T>jest lepsze niż zadeklarowanie valuejako object, ponieważ objectwtedy będziesz musiał śledzić typ użyty dla każdego elementu i rzucić go w kodzie, aby użyć go poprawnie.

Używam go od dłuższego czasu. To jest naprawdę przydatne.

Matheus Rocha
źródło
4

Podobało mi się odpowiedź Fab, ale nie chciałem używać słownika dla mojej sytuacji, więc zastąpiłem listę krotek.

// 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
źródło
3

Przykład użycia 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
źródło
3

Możesz użyć tego kodu, aby wstawić niektóre elementy do pola kombi z tekstem i wartością.

DO#

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
źródło
Proszę wyjaśnić swoje rozwiązanie.
Vaibhav Bajaj
Po prostu dodaj następujące kraje do odpowiednich indeksów w polu kombi. Pojawi się pole kombi z opcją o indeksie 0. Po kliknięciu pola kombi pojawi się następna opcja
Muhammad Ahmad
to nie działa na id, to jest po prostu sposób na indeksowanie listy, nie o to chodziło w pytaniu
Pan Heelis
2

Oprócz odpowiedzi Adama Markowitza, tutaj jest ogólny sposób (względnie) po prostu ustawiania ItemSourcewartości comboboxa enums, przy jednoczesnym pokazywaniu użytkownikowi atrybutu „Opis”. (Można by pomyśleć, że każdy chciałby to zrobić, aby był to .NET jeden liner, ale tak po prostu nie jest i jest to najbardziej elegancki sposób, jaki znalazłem).

Najpierw utwórz tę prostą klasę do konwersji dowolnej wartości Enum na element 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;
    }
}

Po drugie w swojej OnLoadobsługi zdarzeń, trzeba ustawić źródło swojego pola kombi będzie wykaz ComboEnumItemsna podstawie każdy Enumw swoim Enumrodzaju. Można to osiągnąć za pomocą Linq. Następnie ustaw 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";
    }

Teraz użytkownik wybierze z listy przyjaznych dla użytkownika Descriptions, ale wybierze enumwartość, której można użyć w kodzie. Aby uzyskać dostęp do wyboru użytkownika w kodzie, comboBoxUserReadable.SelectedItembędzie ComboEnumItemi comboBoxUserReadable.SelectedValuebędzie EMyEnum.

Bill Pascoe
źródło
1

Możesz użyć ogólnego typu:

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

Przykład użycia prostej 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);
    }
Jan Staecker
źródło
0

Miałem ten sam problem, dodałem nowy ComboBox z wartością tylko w tym samym indeksie, co pierwszy, a potem, gdy zmieniam główną kombinację, indeks w drugim zmienia się w tym samym czasie, a następnie biorę wartość drugiego zestawu i użyj go.

To jest kod:

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
źródło
0

Kreacja klasowa:

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

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

        }

    }
}
Nieograniczona isa
źródło
0

Tak to robi Visual Studio 2013:

Pojedynczy przedmiot:

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

Wiele przedmiotów:

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

Nie trzeba wykonywać przesłonięć klas ani uwzględniać niczego innego. I tak, połączenia comboBox1->SelectedItemi comboBox1->SelectedIndexnadal działają.

Enigma
źródło
0

Jest to podobne do niektórych innych odpowiedzi, ale jest kompaktowe i pozwala uniknąć konwersji na słownik, jeśli masz już listę.

Biorąc pod uwagę ComboBox„combobox” w formularzu systemu Windows i klasę SomeClassz stringwłaściwością type Name,

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

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

Co oznacza, że ​​SelectedItem jest SomeClassobiektem od list, a każdy element w comboboxbędzie wyświetlany przy użyciu jego nazwy.

Alex Smith
źródło
Prawdziwe! Używałem DisplayMemberwcześniej ... Zawsze zapominam, że istnieje. Przyzwyczaiłem się do rozwiązania, które znalazłem, zanim zwróciłem uwagę na tę właściwość, również nie zawsze pomoże. Nie wszystkie klasy mają Namelub Tagmienia, lub mają własności ciągów, które mogą być stosowane arbitralnie jako wyświetlanego tekstu.
Matheus Rocha,
To dobra uwaga. Jeśli możesz zmodyfikować klasę, warto dodać taką właściwość do klasy, na przykład właściwość „ComboBoxText” (która może zwrócić metodę ToString (), jeśli jest dostępna). Alternatywnie, jeśli klasy nie można modyfikować, może być możliwe utworzenie klasy pochodnej, w której można zaimplementować właściwość „ComboBoxText”. Byłoby to tego warte tylko wtedy, gdy trzeba wielokrotnie dodawać klasę do ComboBox. W przeciwnym razie łatwiej jest po prostu użyć słownika, jak wyjaśniono w jednej z pozostałych odpowiedzi.
Alex Smith,
Hej Alex, odpowiedziałem etodą, której zwykle używam w tych przypadkach. Myślę, że to dość blisko tego, co powiedziałeś, a może nie zrozumiałem, co powiedziałeś. Nie wyprowadziłem się z klasy, ponieważ niektóre klasy mogą wymagać od ciebie implementacji metod, których nie chcemy przesłonić (więc mielibyśmy kilka metod za pomocą prostej base.Method();), a także musiałbyś stworzyć klasę pochodną dla każdego innego typu, który chcesz dodać do pól kombi lub pól listy. Klasa, którą stworzyłem, jest elastyczna, można jej używać z każdym rodzajem bez dodatkowego wysiłku. Spójrz poniżej na moją odpowiedź i powiedz mi, co myślisz :)
Matheus Rocha,
Zgadzam się, twoja odpowiedź zdecydowanie wydaje się wygodniejsza niż tworzenie klasy pochodnej dla każdego typu, który chcesz dodać do comboboxa. Dobra robota! Myślę, że w przyszłości, jeśli nie będę mieć łatwo dostępnej właściwości typu „Nazwa”, użyję czegoś takiego jak Twoja odpowiedź lub odpowiedź ze słownika :)
Alex Smith
0

Jest to bardzo proste rozwiązanie dla formularzy Windows, jeśli wszystko jest potrzebne, to końcowa wartość jako (ciąg). Nazwy przedmiotów zostaną wyświetlone w polu kombi, a wybraną wartość można łatwo porównać.

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;

a na module obsługi zdarzeń pobierz wartość (ciąg) wybranej wartości

string test = testComboBox.SelectedValue.ToString();
Esteban Verbel
źródło
0

Lepsze rozwiązanie tutaj;

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

Odzyskaj dane

MessageBox.Show(cmbUser.SelectedValue.ToString());
Orhan Bayram
źródło
Podczas gdy byłem w stanie wypełnić combobox, kliknięcie go powoduje błąd w VS2019 Wykonano wywołanie QueryInterface z prośbą o interfejs klasy widocznej klasy zarządzanej COM „ComboBoxUiaProvider
MC9000