ComboBox:向项目添加文本和值(无绑定源)


202

在C#WinApp中,如何将文本和值同时添加到ComboBox的项目中?我进行了搜索,通常的答案是使用“绑定到源”。但是,在我的情况下,我的程序中没有准备好的绑定源...我该怎么做:

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

Answers:


361

您必须创建自己的类类型并重写ToString()方法以返回所需的文本。这是您可以使用的类的简单示例:

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

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

以下是其用法的简单示例:

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
我们真的需要这个新类ComboboxItem吗?我认为已经有一个叫做ListItem的东西了。
Amr Elgarhy 2010年

15
我相信可能仅在ASP.NET中可用,而在WinForms中不可用。
亚当·马克维兹

1
否。项目是一种单独的类型,仅用于存储项目的数据(文本,值,对其他对象的引用等)。它不是ComboBox的后代,而且非常罕见。
亚当·马克维兹

1
我知道我参加聚会有点晚了,但是我在纯Windows窗体环境中的操作方式是设置一个数据表,向其中添加项目,然后将组合框绑定到该数据表。有人认为应该有一种更清洁的方法,但是我还没有找到一种方法(DisplayMember是您希望文本出现的组合框上的属性,ValueMember是数据的值)
user2366842,2014年

4
我们如何获得“ SelectedValue”或基于值选择项目...请回复
Alpha Gabriel V. Timbol '16

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
完美的作品,这应该是所选的答案。但是我们不能使用comboBox1.SelectedText而不是铸造.SelectedItem并采用.Value吗?
Jeffrey Goines,2014年

@fab,您如何在具有特定键的组合框中找到项目
Smith,

是否可以根据字典关键字在组合框中选择一个项目?例如选择键3,则将选择带有键3的项目。
Dror

此方法不再适用于vs2015。关于无法绑定到新的displaymember和Valuemember引发的异常
Plater

119

您可以像这样使用匿名类:

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

更新:尽管上面的代码将正确显示在组合框中,但您将无法使用SelectedValueSelectedText属性ComboBox。为了能够使用它们,请如下所示绑定组合框:

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
我想稍作修改,因为程序员可能与此同时需要一个for循环。我使用了一个列表,而不是数组。List<Object> items = new List<Object>(); 然后,我可以items.Add( new { Text = "report A", Value = "reportA" } );在循环中使用该方法。
安德鲁

1
安德鲁,您是否获得了List <Object>与SelectedValue属性一起使用?
彼得·皮特洛克

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

2
@Venkat如果使用第二种设置方法,则DataSource可以使用组合框的SelectedValueSelectedText属性,因此不需要进行任何特殊的强制转换。
JPProgrammer

32

您应该使用dynamic对象在运行时解析组合框项目。

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

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

(comboBox.SelectedItem as dynamic).Value

1
这比创建一个单独的类并覆盖ToString()更好。
Don Shrout

1
dynamic仅在C#4和更高版本中可用。(我认为是.NET 4.5)
MickeyfAgain_BeforeExitOfSO

简单快捷地编写!我在VB.net中为SelectedValue做到了这一点:作为字符串的Dim值= CType(Me.SectionIDToComboBox.SelectedItem,Object).Value
Hannington Mambo

1
然后,如何使用“值”设置正确的组合框项目?
戴夫·路德维希

17

您可以使用DictionaryObject而不是创建用于在中添加文本和值的自定义类Combobox

Dictionary对象中添加键和值:

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

将源Dictionary对象绑定到Combobox

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

检索键和值:

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

全文:组合框文字和值


14

这是我想到的一种方式:

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

要更改项目的文本或值,您可以这样操作:

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

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

Windows窗体中没有名为ListItem的类。它仅存在于ASP.NET中,因此您需要在使用它之前编写自己的类,就像@Adam Markowitz在他的回答中所做的一样。

同时检查以下页面,它们可能会有所帮助:


2
除非我没有记错,否则ListItem仅在ASP.NET中可用
Adam Markowitz 2010年

是的:(不幸的是它仅在ASP.net中...所以我现在该怎么办?
Bohn 2010年

那么组合框中的SelectedValue或SelectedText属性的意义是什么?
JSON

11

不知道这是否适用于原始帖子中给出的情况(不要介意这是两年后的事实),但是此示例对我有用:

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

要读回值,必须将SelectedItem属性转换为DictionaryEntry对象,然后可以评估该对象的Key和Value属性。例如:

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

如果仍然有人对此感兴趣,这是一个组合框项目的简单灵活的类,其中包含文本和任何类型的值(非常类似于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;
    }
}

使用<T>胜于将声明为valueas object,因为object您就必须跟踪用于每个项目的类型,并将其转换为代码以正确使用。

我已经在我的项目上使用了一段时间了。真的很方便。


4

我喜欢fab的答案,但不想针对我的情况使用字典,所以我替换了一个元组列表。

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

使用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

您可以使用此代码将一些项目插入带有文本和值的组合框中。

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

请说明您的解决方案。
Vaibhav Bajaj

只需简单地将以下国家/地区添加到combox的相应索引中即可。出现一个带有位于0索引处的选项的combox。如果单击combox,则会显示以下另一个选项
Muhammad Ahmad

这对id无效,这只是对列表建立索引的一种方式,这不是问题所在
Heelis先生

2

除了Adam Markowitz的答案之外,这是一种(相对)简单地将ItemSource组合框的值设置为enums,同时向用户显示'Description'属性的通用方法。(您会认为每个人都希望这样做,因此它将是一个.NET一个衬里,但事实并非如此,这是我发现的最优雅的方法)。

首先,创建一个简单的类,将任何Enum值转换为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;
    }
}

其次在你的OnLoad事件处理程序,您需要设置您的组合框的来源是列表ComboEnumItems基于每个Enum在你的Enum类型。这可以用Linq实现。然后只需设置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";
    }

现在,用户将从用户友好的列表中进行选择Descriptions,但是他们选择的将是enum您可以在代码中使用的值。要访问代码中的用户选择,comboBoxUserReadable.SelectedItem将为ComboEnumItemcomboBoxUserReadable.SelectedValue将为EMyEnum


1

您可以使用通用类型:

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

使用简单的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);
    }

0

我遇到了同样的问题,我要做的就是添加一个新 ComboBox就是在第一个索引中只包含相同索引中值值,然后当我更改主体组合时,第二个索引中的索引同时更改时,我取值第二个组合并使用它。

这是代码:

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

类创建:

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

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

这是Visual Studio 2013的执行方式:

单项:

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

多个项目:

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

无需进行类重写或包含其他任何内容。是的comboBox1->SelectedItemcomboBox1->SelectedIndex通话仍然有效。


0

这与其他一些答案类似,但是很紧凑,并且如果您已经有列表,则可以避免转换为字典。

给定ComboBoxWindows窗体上的“组合框”和SomeClass带有stringtype属性的类Name

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

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

这表示SelectedItem是中的SomeClass对象list,并且其中的每个项目都combobox将使用其名称显示。


真正!我以前用过DisplayMember...我总是忘记它的存在。在适应此属性之前,我已经习惯了找到的解决方案,但它也不会总是有帮助。并非所有类都具有NameTag属性,或者具有可以任意用作显示文本的字符串属性。
Matheus Rocha

这是个好的观点。如果可以修改该类,那么将这样的属性添加到类中可能是值得的,例如,属性“ ComboBoxText”(如果可用,它可以返回ToString()方法)。或者,如果该类不可修改,则有可能创建一个派生类,在其中可以实现'ComboBoxText'属性。仅当您必须多次将类添加到ComboBox时,这才值得。否则,如其他答案之一中所述,仅使用字典更为简单。
亚历克斯·史密斯

嗨,Alex,我已经回答了我在这些情况下通常使用的方法。我认为这与您所说的很接近,或者也许我不明白您所说的话。我不是从类派生的,因为某些类可能会要求您实现我们不想覆盖的方法(因此,我们有一堆简单的方法base.Method();),而且您还必须创建一个派生类对于希望添加到组合框或列表框的每种不同类型。我制作的类非常灵活,可以轻松使用任何类型。在下面找到我的答案,然后告诉我您的想法:)
Matheus Rocha

我同意,您的答案肯定比为要添加到组合框的每种类型创建派生类更方便。不错的工作!我认为,将来如果我没有像“名称”这样的属性,我将使用您的答案或字典答案的方法:)
Alex Smith

0

如果只需要最终值(字符串),则这是Windows窗体的非常简单的解决方案。项目名称将显示在组合框上,并且可以轻松比较所选值。

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;

并在事件处理程序上获取所选值的值(字符串)

string test = testComboBox.SelectedValue.ToString();

0

更好的解决方案;

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

检索数据

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

虽然我能够填满组合框,但单击它会在VS2019中产生此错误。进行了QueryInterface调用,请求COM可见的托管类'ComboBoxUiaProvider的类接口
MC9000
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.