Listbox Control with Tooltip for Each Item






4.91/5 (11 votes)
This article describes how to extend the Windows Forms ListBox control to display a tooltip for each item.

Introduction
This article describes a way of displaying tooltips for items in a Windows Forms ListBox
control. The built-in ToolTip
control allows you to display a single tooltip for the entire listbox
. However, if you want to display separate tooltips for each item in the listbox
, you're out of luck. Fortunately, it's not too difficult to mimic the tooltip behavior yourself. Here, we will look at how to create and use a custom ListBox
control called ToolTipListBox
.
Description of Code
This article contains the complete code required to create a listbox
with different tooltips for each item. We will go through the code in the following sections. The code consists of the following parts:
- Adding
ListBoxItem
objects to theToolTipListBox
control ListBoxItem
classIToolTipDisplayer
interfaceToolTipListBox
class
Adding ListBoxItem Objects to the ToolTipListBox
// Create list of items
ListBoxItem[] items = new ListBoxItem[]
{
new ListBoxItem("Apple", "Malus pumila"),
new ListBoxItem("Banana", "Porcelia macrocarpa"),
new ListBoxItem("Kiwi", "Actinidia deliciosa"),
new ListBoxItem("Papaya", "Carica papaya"),
new ListBoxItem("Mango", "Mangifera indica"),
new ListBoxItem("Tomato", "Lycopersicon esculentum"),
new ListBoxItem("Lychee", "Litchi chinensis"),
new ListBoxItem("Coconut", "Cocos nucifera"),
new ListBoxItem("Tangerine", "Citrus reticulata"),
new ListBoxItem("Avocado", "Persea americana"),
};
// Populate list box
toolTipListBox.Items.AddRange(items);
The code listed above creates an array of ListBoxItem
objects and adds the items to the ToolTipListBox
control. The constructor for each ListBoxItem
takes in the text to display in the listbox
and the tooltip text.
ListBoxItem Class
internal class ListBoxItem : IToolTipDisplayer
{
public string DisplayText { get; private set; }
public string ToolTipText { get; private set; }
// Constructor
public ListBoxItem(string displayText, string toolTipText)
{
DisplayText = displayText;
ToolTipText = toolTipText;
}
// Returns the display text of this item.
public override string ToString()
{
return DisplayText;
}
// Returns the tooltip text of this item.
public string GetToolTipText()
{
return ToolTipText;
}
}
ListBoxItem
is a simple class that is used to represent each item in the listbox. The ToString()
method is overridden from Object
and it returns the text that is displayed in the listbox
. The GetToolTipText()
method returns the tooltip text that is displayed for the item. It implements the IToolTipDisplayer
interface that is described below.
IToolTipDisplayer Interface
/// Interface used by listbox items in ToolTipListBox.
internal interface IToolTipDisplayer
{
string GetToolTipText();
}
The IToolTipDisplayer
interface is used by ToolTipListBox
to get the tooltip text for the listbox
item. The interface has a single method that returns the tooltip text to display for the item. Any object that is added to the listbox
should implement this interface to display tooltip text. As you have seen above, the ListBoxItem
class implements IToolTipDisplayer
.
ToolTipListBox Class
Now we will get to the meat of this article which describes the implementation of ToolTipListBox
. First, let's declare the class and some member variables:
/// ListBox that displays item-specific tooltips.
internal partial class ToolTipListBox : ListBox
{
// The item index that the mouse is currently over
private int _currentItem;
// A value indicating if the current item has been set
private bool _currentItemSet;
// A value indicating if a tooltip is currently being displayed
private bool _toolTipDisplayed;
// Timer that is used to wait for the mouse to hover over an item
private Timer _toolTipDisplayTimer;
// Tooltip control
private ToolTip _toolTip;
Pretty straightforward so far. The class extends the built-in ListBox
control and adds tooltip functionality. Now, let's define the constructor:
public ToolTipListBox()
{
InitializeComponent();
this.MouseMove += listBox_MouseMove;
this.MouseLeave += listBox_MouseLeave;
_currentItemSet = false;
_toolTipDisplayed = false;
_toolTipDisplayTimer = new Timer();
_toolTip = new ToolTip();
// Set the timer interval to the system time that it takes for a tooltip to appear
_toolTipDisplayTimer.Interval = SystemInformation.MouseHoverTime;
_toolTipDisplayTimer.Tick += _toolTipDisplayTimer_Tick;
}
InitializeComponent()
is automatically added by Visual Studio when you create a new User Control. We add handlers for the MouseMove
and MouseLeave
events of the listbox
. Then we initialize the member variables. Then we set the timer to raise the Tick
event after the standard system time for a tooltip (SystemInformation.MouseHoverTime
). Now, let's define the MouseMove
event handler for the listbox
:
private void listBox_MouseMove(object sender, MouseEventArgs e)
{
// Get the item that the mouse is currently over
Point cursorPoint = Cursor.Position;
cursorPoint = this.PointToClient(cursorPoint);
int itemIndex = this.IndexFromPoint(cursorPoint);
if (itemIndex == ListBox.NoMatches)
{
// Mouse is over empty space in the listbox so hide tooltip
_toolTip.Hide(this);
_currentItemSet = false;
_toolTipDisplayed = false;
_toolTipDisplayTimer.Stop();
}
else if (!_currentItemSet)
{
// Mouse is over a new item so start timer to display tooltip
_currentItem = itemIndex;
_currentItemSet = true;
_toolTipDisplayTimer.Start();
}
else if (itemIndex != _currentItem)
{
// Mouse is over a different item so hide tooltip and restart timer
_currentItem = itemIndex;
_toolTipDisplayTimer.Stop();
_toolTipDisplayTimer.Start();
_toolTip.Hide(this);
_toolTipDisplayed = false;
}
}
This event is raised whenever the mouse is over the listbox
(whether it's moving or not). First, we determine which item index the mouse is over. We can use the PointToClient()
and IndexFromPoint()
methods of the listbox
to get this. Now, we have several cases depending on the index that the mouse is over:
itemIndex == ListBox.NoMatches
This condition is satisfied when the mouse is over empty space in the listbox
. This means that we should hide the tooltip and stop the tooltip display timer.
!_currentItemSet
This condition is satisfied when the mouse has just began moving over a listbox
item. In this case, we want to set the current item and start the timer to display the tooltip.
itemIndex != _currentItem
This condition is satisfied when the mouse has moved over a new item that is different from the currently set one. In this case, we should set the current item to the new item, hide the tooltip if it's currently being displayed and restart the tooltip display timer.
private void listBox_MouseLeave(object sender, EventArgs e)
{
// Mouse has left listbox so stop timer (tooltip is automatically hidden)
_currentItemSet = false;
_toolTipDisplayed = false;
_toolTipDisplayTimer.Stop();
}
The MouseLeave
event is raised when the mouse is no longer over the listbox
. In this case, we want to reset the current item and stop the tooltip display timer.
void _toolTipDisplayTimer_Tick(object sender, EventArgs e)
{
// Display tooltip text since the mouse has hovered over an item
if (!_toolTipDisplayed && _currentItem != ListBox.NoMatches &&
_currentItem < this.Items.Count)
{
IToolTipDisplayer toolTipDisplayer = this.Items[_currentItem] as IToolTipDisplayer;
if (toolTipDisplayer != null)
{
_toolTip.SetToolTip(this, toolTipDisplayer.GetToolTipText());
_toolTipDisplayed = true;
}
}
}
The Tick
event of the timer is raised after the standard mouse hover time has passed. When this happens, we know that the mouse has been on the same item for some time so we should display the tooltip for that item. The tooltip text for the item is obtained by calling the GetToolTipText()
method of the current item. Of course, this will only work if the item has implemented the IToolTipDisplayer
interface.
Conclusion
That's it! The complete code listed here is available in the attached .zip file. The project was created using Visual C# 2010 Express. There are several other ways of displaying tooltips, but I found that this way is clean since it hides the implementation details in a custom control. The ToolTipListBox
control can be added to a form just like any built-in control and the IToolTipDisplayer
interface can be added to any existing object that you add to the listbox
.