ComboBox: Thêm văn bản và giá trị vào một mục (không có nguồn ràng buộc)


202

Trong C # WinApp, làm cách nào tôi có thể thêm cả Văn bản và Giá trị vào các mục trong ComboBox của mình? Tôi đã thực hiện tìm kiếm và thông thường các câu trả lời đang sử dụng "Liên kết với nguồn" .. nhưng trong trường hợp của tôi, tôi không có nguồn ràng buộc sẵn sàng trong chương trình của mình ... Làm thế nào tôi có thể làm điều gì đó như thế này:

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

Câu trả lời:


361

Bạn phải tạo loại lớp của riêng mình và ghi đè phương thức ToString () để trả về văn bản bạn muốn. Đây là một ví dụ đơn giản về một lớp bạn có thể sử dụng:

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

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

Sau đây là một ví dụ đơn giản về cách sử dụng của nó:

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
chúng ta có thực sự cần lớp ComboboxItem mới này không? Tôi nghĩ rằng có một cái đã tồn tại được gọi là ListItem.
Amr Elgarhy

15
Tôi tin rằng chỉ có thể có sẵn trong ASP.NET chứ không phải WinForms.
Adam Markowitz

1
Không. Mục này là một loại riêng biệt chỉ được sử dụng để lưu trữ dữ liệu của các mục (văn bản, giá trị, tham chiếu đến các đối tượng khác, v.v.). Nó không phải là hậu duệ của ComboBox và nó sẽ cực kỳ hiếm khi xảy ra.
Adam Markowitz

1
Tôi biết tôi đến bữa tiệc muộn, nhưng tôi đã làm điều này trong môi trường dạng cửa sổ thuần túy là thiết lập một dữ liệu, thêm các mục vào nó và liên kết hộp tổ hợp với dữ liệu. Mọi người sẽ nghĩ rằng nên có cách làm sạch hơn, nhưng tôi chưa tìm thấy (DisplayMember là thuộc tính trên hộp tổ hợp bạn muốn xuất hiện, ValueMember cho Giá trị của dữ liệu)
user2366842

4
làm thế nào để chúng tôi nhận được "Chọn giá trị" hoặc chọn mục dựa trên giá trị ... vui lòng trả lời
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;

2
Hoạt động hoàn hảo và đây nên là câu trả lời được lựa chọn. Nhưng chúng ta không thể sử dụng comboBox1.SelectedText thay vì truyền .SelectedItem và lấy .Value?
Jeffrey Goines

@fab làm thế nào để bạn tìm thấy mục trong combobox với một khóa nhất định
Smith

Có thể chọn một mục trong hộp tổ hợp dựa trên Khóa từ điển không? như chọn Khóa 3 để Mục có Khóa 3 sẽ được chọn.
Dror

Phương pháp này không còn hoạt động cho vs2015. Các trường hợp ngoại lệ bị ném về việc không thể liên kết với người hiển thị mới và Valuemember
Plater

119

Bạn có thể sử dụng lớp ẩn danh như thế này:

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

CẬP NHẬT: Mặc dù mã ở trên sẽ hiển thị đúng trong hộp tổ hợp, bạn sẽ không thể sử dụng SelectedValuehoặc SelectedTextthuộc tính của ComboBox. Để có thể sử dụng chúng, hãy liên kết hộp tổ hợp như dưới đây:

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
Tôi muốn sửa đổi điều này một chút bởi vì một lập trình viên có thể sẽ cần một vòng lặp for cùng với điều này. Thay vì một mảng tôi đã sử dụng một danh sách List<Object> items = new List<Object>(); Sau đó tôi có thể sử dụng phương thức items.Add( new { Text = "report A", Value = "reportA" } );trong vòng lặp.
Andrew

1
Andrew, bạn đã có được Danh sách <Object> để làm việc với thuộc tính ChọnValue chưa?
Peter PitLock

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

2
@Venkat nếu bạn sử dụng giải pháp thứ hai đặt DataSourcebạn có thể sử dụng SelectedValuehoặc SelectedTextcác thuộc tính của combobox, do đó không cần phải thực hiện bất kỳ phép đúc đặc biệt nào.
Chương trình JP

32

Bạn nên sử dụng dynamicđối tượng để giải quyết mục combobox trong thời gian chạy.

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

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

(comboBox.SelectedItem as dynamic).Value

1
Điều này tốt hơn nhiều so với việc tạo một lớp riêng và ghi đè ToString ().
Don Shrout

1
động chỉ có sẵn trong C # 4 trở lên. (.NET 4.5 tôi nghĩ)
MickeyfAgain_B BeforeExitOfSO

Đơn giản và nhanh hơn để viết! Tôi đã làm điều này cho ChọnValue trong VB.net: Dim Value As String = CType (Me.SectionIDToComboBox.SelectedItem, Object) .Value
Hannington Mambo

1
Sau đó, làm thế nào để đặt mục hộp tổ hợp chính xác bằng cách sử dụng "Giá trị"?
Dave Ludwig

17

Bạn có thể sử dụng DictionaryObject thay vì tạo một lớp tùy chỉnh để thêm văn bản và giá trị trong mộtCombobox .

Thêm khóa và giá trị trong DictionaryĐối tượng:

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

Liên kết đối tượng từ điển nguồn với Combobox:

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

Lấy khóa và giá trị:

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

Nguồn đầy đủ: Combobox Text nd Value


14

Đây là một trong những cách mà tôi nghĩ đến:

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

Và để thay đổi văn bản hoặc giá trị của một mục, bạn có thể làm như thế này:

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

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

Không có lớp nào được gọi là ListItem trong Windows Forms . Nó chỉ tồn tại trong ASP.NET , vì vậy bạn sẽ cần phải viết lớp của riêng mình trước khi sử dụng nó, giống như @Adam Markowitz đã làm trong câu trả lời của mình .

Ngoài ra kiểm tra các trang này, họ có thể giúp:


2
Trừ khi tôi nhầm, ListItem chỉ có sẵn trong ASP.NET
Adam Markowitz

vâng :( thật không may, nó chỉ có trong ASP.net ... vậy bây giờ tôi có thể làm gì?
Bohn

Sau đó, điểm của các thuộc tính chọnValue hoặc chọnText trong hộp tổ hợp là gì?
JSON

11

Không biết điều này có hiệu quả với tình huống được đưa ra trong bài viết gốc không (đừng bận tâm đến thực tế rằng đây là hai năm sau), nhưng ví dụ này hoạt động với tôi:

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

Để đọc lại giá trị của bạn, bạn sẽ phải chuyển thuộc tính ChọnItem thành đối tượng DictionaryEntry và sau đó bạn có thể đánh giá các thuộc tính Khóa và Giá trị của thuộc tính đó. Ví dụ:

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

Nếu bất cứ ai vẫn quan tâm đến điều này, thì đây là một lớp đơn giản và linh hoạt cho một mục combobox có văn bản và giá trị thuộc bất kỳ loại nào (rất giống với ví dụ của 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;
    }
}

Sử dụng <T>là tốt hơn so với khai báo valueobject, bởi vì vớiobject sau đó bạn phải theo dõi loại bạn đã sử dụng cho từng mục và sử dụng mã đó trong mã của bạn để sử dụng đúng cách.

Tôi đã sử dụng nó cho các dự án của tôi khá lâu rồi. Nó thực sự tiện dụng.


4

Tôi thích câu trả lời của fab nhưng không muốn sử dụng từ điển cho tình huống của mình nên tôi đã thay thế một danh sách các bộ dữ liệu.

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

Một ví dụ sử dụng 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

Bạn có thể sử dụng mã này để chèn một số mục vào hộp tổ hợp có văn bản và giá trị.

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

Hãy giải thích giải pháp của bạn.
Vaibhav Bajaj

Đơn giản là vậy, hãy thêm các quốc gia sau vào các chỉ mục tương ứng của chúng trong combox. Khi bạn chạy nó. Một combox xuất hiện với tùy chọn ở mức 0. Chỉ số nếu bạn nhấp vào combox, tùy chọn khác sau đây sẽ hiển thị
Muhammad Ahmad

Điều này không hiệu quả với id, đây đơn giản chỉ là một cách để lập chỉ mục cho danh sách, đó không phải là câu hỏi về điều gì
Mr Heelis

2

Ngoài câu trả lời của Adam Markowitz, đây là cách mục đích chung (tương đối) chỉ đơn giản là đặt các ItemSourcegiá trị của hộp tổ hợp thành enums, đồng thời hiển thị thuộc tính 'Mô tả' cho người dùng. (Bạn sẽ nghĩ mọi người đều muốn làm điều này để nó sẽ là một .NET lớp lót , nhưng thực tế không phải vậy, và đây là cách thanh lịch nhất mà tôi đã tìm thấy).

Đầu tiên, tạo lớp đơn giản này để chuyển đổi bất kỳ giá trị Enum nào thành một mục 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;
    }
}

Thứ hai, trong OnLoadtrình xử lý sự kiện của bạn , bạn cần đặt nguồn của hộp tổ hợp thành một danh sách ComboEnumItemsdựa trên mỗi loại Enumtrong Enumloại của bạn . Điều này có thể đạt được với Linq. Sau đó, chỉ cần đặt 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";
    }

Bây giờ người dùng sẽ chọn từ danh sách người dùng thân thiện của bạn Descriptions, nhưng những gì họ chọn sẽ là enumgiá trị mà bạn có thể sử dụng trong mã. Để truy cập lựa chọn của người dùng trong mã, comboBoxUserReadable.SelectedItemsẽ là ComboEnumItemcomboBoxUserReadable.SelectedValuesẽ là EMyEnum.


1

Bạn có thể sử dụng Loại chung:

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

Ví dụ về sử dụng kiểu int đơn giản:

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

Tôi đã có cùng một vấn đề, những gì tôi đã làm là thêm một cái mới ComboBox giá trị chỉ với giá trị trong cùng một chỉ mục rồi đến giá trị đầu tiên và sau đó khi tôi thay đổi kết hợp chính, chỉ số trong lần thứ hai thay đổi cùng một lúc, sau đó tôi nhận giá trị của combo thứ hai và sử dụng nó.

Đây là mã:

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

Lớp tạo:

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

Mã 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

Đây là cách Visual Studio 2013 thực hiện:

Một vật thể:

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

Nhiều mặt hàng:

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

Không cần phải ghi đè lớp hoặc bao gồm bất cứ điều gì khác. Và có comboBox1->SelectedItemcomboBox1->SelectedIndexcác cuộc gọi vẫn hoạt động.


0

Điều này tương tự với một số câu trả lời khác, nhưng nhỏ gọn và tránh chuyển đổi sang từ điển nếu bạn đã có một danh sách.

Đưa ra một ComboBox" hộp tổ hợp" trên biểu mẫu cửa sổ và một lớp SomeClasscó thuộc tính stringloại Name,

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

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

Điều đó có nghĩa là ChọnItem là một SomeClassđối tượng listvà mỗi mục trong đó comboboxsẽ được hiển thị bằng tên của nó.


Thật! Tôi đã sử dụng DisplayMembertrước đây ... Tôi luôn quên nó tồn tại. Tôi đã quen với giải pháp mà tôi tìm thấy trước khi tôi chú ý đến tài sản này, nó cũng sẽ không luôn giúp ích. Không phải tất cả các lớp đều có một Namehoặc thuộc Tagtính hoặc có một thuộc tính chuỗi có thể được sử dụng tùy ý làm văn bản hiển thị.
Matheus Rocha

đây là một quan điểm tốt. Nếu bạn có thể sửa đổi lớp thì có thể đáng để thêm thuộc tính đó vào lớp, ví dụ: thuộc tính 'ComboBoxText' (có thể trả về phương thức ToString () nếu có). Ngoài ra, nếu lớp không thể sửa đổi, có thể tạo một lớp dẫn xuất trong đó thuộc tính 'ComboBoxText' có thể được triển khai. Điều này sẽ chỉ có giá trị nếu bạn phải thêm lớp vào ComboBox nhiều lần. Mặt khác, đơn giản hơn là chỉ sử dụng một từ điển như được giải thích trong một trong những câu trả lời khác.
Alex Smith

Này Alex, tôi đã đưa ra câu trả lời với ethod tôi thường sử dụng trong những trường hợp này. Tôi nghĩ nó khá gần với những gì bạn nói hoặc có thể tôi không hiểu những gì bạn nói. Tôi không xuất phát từ lớp vì một số lớp có thể yêu cầu bạn thực hiện các phương thức mà chúng tôi không muốn ghi đè (vì vậy chúng tôi có một loạt các phương thức đơn giản base.Method();), bạn cũng phải tạo một lớp phái sinh cho mỗi loại khác nhau, bạn muốn thêm vào hộp tổ hợp hoặc hộp danh sách. Lớp tôi làm rất linh hoạt, bạn có thể sử dụng với bất kỳ loại nào mà không cần nỗ lực thêm. Nhìn bên dưới để biết câu trả lời của tôi và cho tôi biết bạn nghĩ gì :)
Matheus Rocha

Tôi đồng ý, câu trả lời của bạn chắc chắn có vẻ thuận tiện hơn so với việc tạo một lớp dẫn xuất cho mỗi loại bạn muốn thêm vào một hộp tổ hợp. Công việc tốt! Tôi nghĩ trong tương lai nếu tôi không có tài sản như 'Tên' thì tôi sẽ sử dụng một cái gì đó như câu trả lời của bạn hoặc câu trả lời từ điển :)
Alex Smith

0

Đây là một giải pháp rất đơn giản cho các biểu mẫu windows nếu tất cả cần thiết là giá trị cuối cùng dưới dạng (chuỗi). Tên của các mặt hàng sẽ được hiển thị trên Hộp Combo và có thể dễ dàng so sánh giá trị được chọn.

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;

và trên trình xử lý sự kiện lấy giá trị (chuỗi) của giá trị được chọn

string test = testComboBox.SelectedValue.ToString();

0

Giải pháp tốt hơn ở đây;

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

Dữ liệu truy xuất

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

Trong khi tôi có thể điền vào hộp tổ hợp, nhấp vào nó sẽ gây ra lỗi này trong VS2019 Một cuộc gọi QueryInterface đã được thực hiện yêu cầu giao diện lớp của lớp được quản lý hiển thị COM 'ComboBoxUiaProvider
MC9000
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.