Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invalidate only a single item in ListBox

Is there anyway to only invalidate a single item in a ListBox? There seems to be no method of getting the rectangle of an item, or even if a specific item is visible (aside from calling IndexFromPoint for every pixel in the control / at least every pixel in one column).

This is for C# WinForms (not WPF).

More information about what I am trying to do:

I have a ListBox with many items in it, and I want a set of "buttons" to appear on items that you hover over (such as a red X for remove). I have this working great, except that on lists with 10 or more items, each time you hover over a new item it causes a visible redraw since I invalidate the entire control. The data is not changed, only the display is changed.

Edit: More Information and Previous Attempts

I already subclass ListBox and perform my drawing in OnDrawItem so protected methods of ListBox can be used.

I have tried the following with varying levels of success. The variable this is the extended ListBox, index is the item to drawn over, old_index is the item previously being drawn over.

// Causes flicker of entire list, but works
this.Invalidate();

// Causes flicker of selected item, but works
int sel_index = this.SelectedIndex;
this.SelectedIndex = old_index;
this.SelectedIndex = index;
this.SelectedIndex = sel_index;

// Does not work
if (old_index >= 0)
  this.RefreshItem(old_index);
if (index >= 0)
  this.RefreshItem(index);
like image 579
coderforlife Avatar asked Feb 24 '23 08:02

coderforlife


2 Answers

Yes, but you have to create your own version of the listbox by inheriting it and exposing the RefreshItem method that Microsoft is hiding from you:

public class ListBoxEx : ListBox
{
  public new void RefreshItem(int index)
  {
    base.RefreshItem(index);
  }
}
like image 37
LarsTech Avatar answered Feb 25 '23 22:02

LarsTech


Okay, I was being silly. Thanks to @LarsTech I decided to look over the entire list of ListBox functions again and found the appropriate one: GetItemRectangle and it is even public! I don't know how I missed this for the last hour...

The working solution is:

if (old_index >= 0)
  this.Invalidate(this.GetItemRectangle(old_index));
if (index >= 0)
  this.Invalidate(this.GetItemRectangle(index));

Which still produces a little flickering but significantly less (only visible when I mouse over many very quickly where before moving a single item caused it).

like image 163
coderforlife Avatar answered Feb 25 '23 23:02

coderforlife