blockheadjr
blockheadjr

Reputation: 53

WinForms: Simplest way to change listbox text color on the fly?

Looking for a simple way to add color text (or bold text) to a listbox item (the solutions I've seen in Stackoverflow have seemed overly complicated for my needs).

I've been adding comments to my listbox via this code:

listBox1.Items.Add("Test complete!");

This line is peppered throughout my code. I'd love to be able to modify the occasional text with color such that a line like "Test complete!" shows up in green.

Is there a simple, on-the-fly solution to this?

Upvotes: 3

Views: 12507

Answers (2)

Bilal Bashir
Bilal Bashir

Reputation: 1493

You can but takes a little a bit of work to setup, not really that complicated if you are just looking to setup the font color or font.

You have to add a handler to the DrawItem event.

this.listBox1.DrawItem += new DrawItemEventHandler(listBox1_DrawItem);

and here is a pretty simple handler that does what you are looking for.

void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
    Graphics g = e.Graphics;
    Dictionary<string, object> props = (this.listBox1.Items[e.Index] as Dictionary<string, object>);
    SolidBrush backgroundBrush = new SolidBrush(props.ContainsKey("BackColor") ? (Color)props["BackColor"] : e.BackColor);
    SolidBrush foregroundBrush = new SolidBrush(props.ContainsKey("ForeColor") ? (Color)props["ForeColor"] : e.ForeColor);
    Font textFont = props.ContainsKey("Font") ? (Font)props["Font"] : e.Font;
    string text = props.ContainsKey("Text") ? (string)props["Text"] : string.Empty;
    RectangleF rectangle = new RectangleF(new PointF(e.Bounds.X, e.Bounds.Y), new SizeF(e.Bounds.Width, g.MeasureString(text, textFont).Height));

    g.FillRectangle(backgroundBrush, rectangle);
    g.DrawString(text, textFont, foregroundBrush, rectangle);

    backgroundBrush.Dispose();
    foregroundBrush.Dispose();
    g.Dispose();
}

and then to add items to the ListBox you can do this.

this.listBox1.Items.Add(new Dictionary<string, object> { { "Text", "Something, something"},
                                                         { "BackColor", Color.Red },
                                                         { "ForeColor", Color.Green}});
this.listBox1.Items.Add(new Dictionary<string, object> { { "Text", "darkside!!" },
                                                         { "BackColor", Color.Blue },
                                                         { "ForeColor", Color.Green },
                                                         { "Font", new Font(new Font("Arial", 9), FontStyle.Bold) } });

Fairly simple I think.

Tada

Upvotes: 5

Anthony
Anthony

Reputation: 9571

There's no way to do with without drawing the items in the ListBox yourself. However, this isn't hard to accomplish with code. A trivial implementation that assumes the items aren't removed/reordered in the list box involves just keeping a dictionary mapping an index to a color and then drawing it with something like this:

private void ListBox_DrawItem(object sender, DrawItemEventArgs e)
{
    var isItemSelected = ((e.State & DrawItemState.Selected) == DrawItemState.Selected);

    Color foreColor;
    if (!this.mColorsByIndex.TryGetValue(e.Index, out foreColor))
    {
        foreColor = isItemSelected ? SystemColors.HighlightText : this.mListBox.ForeColor;
    }

    var backColor = isItemSelected ? SystemColors.Highlight : this.mListBox.BackColor;
    using (var backBrush = new SolidBrush(backColor))
    {
        e.Graphics.FillRectangle(backBrush, e.Bounds);
    }

    var item = this.mListBox.Items[e.Index];
    var itemText = this.mListBox.GetItemText(item);
    const TextFormatFlags formatFlags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter;
    TextRenderer.DrawText(e.Graphics, itemText, e.Font, e.Bounds, foreColor, formatFlags);
}

In terms of custom drawing in WinForms, this is almost as simple as it gets.

Note that ListBox.Items.Add returns the index of the item you added.

Keeping up with the color associations gets a little harder if you remove/change/reorder items in the ListBox, but that complicates tracking the color associations, not the drawing itself.

Upvotes: 0

Related Questions