Search code examples
c#winformscombobox

How to hide square brackets in my UI output using dictionary in Combobox?


I'm trying to hide the square brackets in my UI output.

enter image description here

I think it's a pretty easy workaround, but I can't figure it out.

My code for adding items into Combobox:

conn_mode.DataSource = new Dictionary<string, string>()
{
    {"1", "WiFi"},
    {"2", "GSM"},
    {"3", "Offline"},
}.ToList();
conn_mode.ValueMember = "Key";
conn_mode.DisplayMember = "Value";

And I'm using this code to align items in combobox into center:

private void cur_mul_DrawItem(object sender, DrawItemEventArgs e)
{       
    ComboBox cbx = sender as ComboBox;
    if (cbx != null)
    {
    // Always draw the background
    e.DrawBackground();

    // Drawing one of the items?
    if (e.Index >= 0)
    {
        // Set the string alignment.  Choices are Center, Near and Far
        StringFormat sf = new StringFormat();
        sf.LineAlignment = StringAlignment.Center;
        sf.Alignment = StringAlignment.Center;

        // Set the Brush to ComboBox ForeColor to maintain any ComboBox color settings
        // Assumes Brush is solid
        Brush brush = new SolidBrush(cbx.ForeColor);

        // If drawing highlighted selection, change brush
        if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            brush = SystemBrushes.HighlightText;

        // Draw the string
        e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, brush, e.Bounds, sf);
    }
}

Solution

  • Always call the GetItemText method to get item's text regardless how the ComboBox is populated.

    var cbx = sender as ComboBox;
    var itemText = cbx.GetItemText(cbx.Items[e.Index]);
    
    e.Graphics.DrawString(itemText, ...);
    

    If you need to display a formatted string like ValueMember + DisplayMember, your data source here is Dictionary<string, string>, then the items are a collection of type KeyValuePair<string, string>. Therefore:

    var cbx = sender as ComboBox;
    var item = (KeyValuePair<string, string>)cbx.Items[e.Index];
    var itemText = $"{item.Key}, {item.Value}";
    
    e.Graphics.DrawString(itemText, ...);
    

    Otherwise, you'll get what the .ToString() method override returns for the KeyValuePair<TKey, TValue> type when you pass cbx.Items[e.Index].ToString().

    Side Notes

    • You must dispose of sf and brush instances or create them by using the using statement.
    var cbx = sender as ComboBox;
    var item = (KeyValuePair<string, string>)cbx.Items[e.Index];
    var itemText = $"{item.Key}, {item.Value}";
    var foreColor = cbx.ForeColor;
    
    if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
        foreColor = SystemColors.HighlightText;
    
    using (var brush = new SolidBrush(foreColor))
    using (var sf = new StringFormat(StringFormat.GenericTypographic))
    {
        sf.Alignment = sf.LineAlignment = StringAlignment.Center;
        e.Graphics.DrawString(itemText, cbx.Font, brush, e.Bounds, sf);
    }
    
    • Use the TextRenderer instead to draw the text on controls.
    var cbx = sender as ComboBox;
    var item = (KeyValuePair<string, string>)cbx.Items[e.Index];
    var itemText = $"{item.Key}, {item.Value}";
    var foreColor = cbx.ForeColor;
    
    if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
        foreColor = SystemColors.HighlightText;
    
    TextRenderer.DrawText(e.Graphics, itemText, cbx.Font, e.Bounds, foreColor, 
        TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);