7

I'm using OwnerDrawFixed as a DrawMode for the custom ListBox control in my WinForms app.

I want to repaint the background (or do some other action) of the ListBoxItem when the user hovers over the listbox item, that is, at the MouseMove...

DrawItemState.HotLight never works for the ListBox, so i wonder how to emulate it, how to workaround this problem.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Beaver
  • 257
  • 5
  • 12

2 Answers2

11

It took me only two years to find the answer for you, but here it is:

The DrawItemState.HotLight only applies to owner drawn menus, not the listbox. For the ListBox, you have to keep track of the item yourself:

public partial class Form1 : Form
{
  private int _MouseIndex = -1;

  public Form1()
  { InitializeComponent(); }

  private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
  {
    Brush textBrush = SystemBrushes.WindowText;

    if (e.Index > -1)
    {
      if (e.Index == _MouseIndex)
      {
        e.Graphics.FillRectangle(SystemBrushes.HotTrack, e.Bounds);
        textBrush = SystemBrushes.HighlightText;
      }
      else
      {
        if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
        {
          e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds);
          textBrush = SystemBrushes.HighlightText;
        }
        else
          e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
      }
      e.Graphics.DrawString(listBox1.Items[e.Index].ToString(), e.Font, textBrush, e.Bounds.Left + 2, e.Bounds.Top);
    }
  }

  private void listBox1_MouseMove(object sender, MouseEventArgs e)
  {
    int index = listBox1.IndexFromPoint(e.Location);
    if (index != _MouseIndex)
    {
      _MouseIndex = index;
      listBox1.Invalidate();
    }
  }

  private void listBox1_MouseLeave(object sender, EventArgs e)
  {
    if (_MouseIndex > -1)
    {
      _MouseIndex = -1;
      listBox1.Invalidate();
    }
  }
}
LarsTech
  • 80,625
  • 14
  • 153
  • 225
  • 2
    Well, 2 years later you helped me too! ;) Nice, simple way for 'hot tracking' in a listbox...thanks! – ChandlerPelhams Oct 06 '11 at 20:30
  • 1
    And LarsTech will help many for many years to come...I was looking for a similar answer and found it here. Thanks. – ThN Dec 02 '11 at 17:33
  • How can this be done for a combobox? Combobox doesn't have IndexFromPoint. – Adam Bruss Feb 17 '12 at 15:45
  • 1
    @AdamBruss The mouse events only report on the TextBox part of the ComboBox, too. Shouldn't really be an issue though with a ComboBox because there the DrawItemState.Selected is being called on every mouse movement. Just ignore the `MouseIndex` part of the code. For the ComboBox, the DrawItemState.Selected is essentially the same thing as the hot index. To test, I changed my `FillRectangle` to use a red brush and it painted every item red my mouse was hovering over. – LarsTech Feb 17 '12 at 16:34
0

This solution will just weigh your code down; just try this:

If e.State And DrawItemState.Selected Then
                    e.Graphics.FillRectangle(SystemBrushes.HotTrack, e.Bounds)
                    e.Graphics.DrawString(drv, Me.Font, SystemBrushes.HighlightText, e.Bounds.X + 18, e.Bounds.Y + 1)
                Else
                    e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds)
                    e.Graphics.DrawString(drv, Me.Font, SystemBrushes.ControlText, e.Bounds.X + 18, e.Bounds.Y + 1)
End If

This operation: e.State And DrawItemState.Selected verifies the item is hovered. No need to put a whole pack of code just to know what item is hovered.

Flexo
  • 87,323
  • 22
  • 191
  • 272