Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Owner drawn listbox not drawing previously selected item

I want to increase the height of the items in a listbox - to pad them internally, basically. Other than that, I don't want to change the default listbox behavior. I have followed the MSDN example for doing owner drawn list items, but I have a problem. The default listbox draws the items in black and the selected item in white with a blue highlight. To accomplish this same functionality I used the following code in the DrawItem event handler:

private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
    {
        Brush b = (e.Index == ((ListBox)sender).SelectedIndex ? Brushes.White : Brushes.Black);
        e.DrawBackground();
        e.Graphics.DrawString(listBox1.Items[e.Index].ToString(), e.Font, b, new Rectangle(new Point(e.Bounds.X, e.Bounds.Y + 2), e.Bounds.Size));
        e.DrawFocusRectangle();
    }

This seems to work fine except when I click around the list. The selected item does show as white text on a blue background, but the previously selected item remains white. It seems like the item I select is redrawn but the previously selected item is not. If I move to another control, the listbox redraws fine. What am I missing?

like image 200
L Fitz Avatar asked Oct 16 '25 15:10

L Fitz


2 Answers

To add padding to list box, just set .ItemHeight of list box to some height.

Otherwise, if you want to do owner draw, instead of selecting color manually, use e.ForeColor. Like this:

Brush b = new SolidBrush(e.ForeColor);

Note, that in such case you would have to paint background for selected item too. Checking state of list box item could be performed like this:

e.Graphics.FillRectangle((e.State & DrawItemState.Selected) != 0 ? SystemBrushes.Highlight : SystemBrushes.Window, new Rectangle(new Point(e.Bounds.X, e.Bounds.Y + 2), e.Bounds.Size));
like image 63
Algirdas Avatar answered Oct 18 '25 04:10

Algirdas


Answer: ListBox.SelectedIndex is very irrational (like Hans said), but e.ForeColor is correct enough. Use that instead.

Replace your code: e.Index == ((ListBox)sender).SelectedIndex

with e.ForeColor == SystemColors.HighlightText

 

Supporting Data:

Add this line to the top of listBox1_DrawItem:

Console.WriteLine("e.Index=" + e.Index + " SelectedIndex=" + 
  listBox1.SelectedIndex + " ForeColor=" + e.ForeColor);

It produces output like this ( // annotated )

// Added 4 items to listbox
e.Index=0 SelectedIndex=-1 ForeColor=Color [WindowText]
e.Index=1 SelectedIndex=-1 ForeColor=Color [WindowText]
e.Index=2 SelectedIndex=-1 ForeColor=Color [WindowText]
e.Index=3 SelectedIndex=-1 ForeColor=Color [WindowText]

// MouseDown on item 0
e.Index=0 SelectedIndex=-1 ForeColor=Color [WindowText]
e.Index=0 SelectedIndex=0 ForeColor=Color [HighlightText]
e.Index=0 SelectedIndex=0 ForeColor=Color [HighlightText]
e.Index=0 SelectedIndex=0 ForeColor=Color [HighlightText]
e.Index=0 SelectedIndex=0 ForeColor=Color [HighlightText]
e.Index=0 SelectedIndex=0 ForeColor=Color [HighlightText]
e.Index=1 SelectedIndex=0 ForeColor=Color [WindowText]
e.Index=2 SelectedIndex=0 ForeColor=Color [WindowText]
e.Index=3 SelectedIndex=0 ForeColor=Color [WindowText]
e.Index=0 SelectedIndex=0 ForeColor=Color [HighlightText]
// MouseUp on item 0 (no DrawItem events)

// MouseDown for item 1
e.Index=0 SelectedIndex=0 ForeColor=Color [HighlightText]
e.Index=0 SelectedIndex=0 ForeColor=Color [WindowText]
e.Index=1 SelectedIndex=1 ForeColor=Color [HighlightText]
e.Index=1 SelectedIndex=1 ForeColor=Color [HighlightText]
// MouseUp for item 1 (no DrawItem events)

// MouseDown for item 2
e.Index=1 SelectedIndex=1 ForeColor=Color [HighlightText]
e.Index=1 SelectedIndex=1 ForeColor=Color [WindowText]
e.Index=2 SelectedIndex=2 ForeColor=Color [HighlightText]
e.Index=2 SelectedIndex=2 ForeColor=Color [HighlightText]

// Drag to item 3
e.Index=2 SelectedIndex=2 ForeColor=Color [HighlightText]
e.Index=2 SelectedIndex=2 ForeColor=Color [WindowText]
e.Index=3 SelectedIndex=3 ForeColor=Color [HighlightText]
e.Index=3 SelectedIndex=3 ForeColor=Color [HighlightText]
// MouseUp over item 3 (no DrawItem events)

So basically... ListBox maybe draws more than we want, but you end up getting the right colors during the last draws.

I also recommend DoubleBuffering.

like image 36
Nathan Schubkegel Avatar answered Oct 18 '25 03:10

Nathan Schubkegel