Custom tool tips (hints) for WinForms
TL;DR
The Idea
My general idea was to place tip window under the hovered control, but not just near the cursor. Also I wanted to draw tip in a little bit another way. So, to do this I need:
- override tip appearance location (window position);
- override tip boundaries (window size);
- override tip drawing.
I don’t want to say that this idea was only my, I saw it some application and I like it 😊
The Journey
From development point of view, to make custom behavior for tool tips in WinForms we have 3 ways:
- use standard class and try to override it’s behavior with component-provided events and properties;
- reuse original source code to add needed functionality;
- implement own component with needed behavior.
And I tried all of them and the result looks very exciting 😃
We cannot inherit and try to completely override class behavior with language-given possibilities
because there’s no virtual
functions exist to override.
ToolTip Events
ToolTip component propose to us instruments to customize it’s behavior, including:
- it’s size, but not position (which is really hard to understand to me why?);
- it’s content, i.e. custom drawing.
⚡ ToolTip.Popup
event gives us event arguments with the following useful properties:
AssociatedWindow
- possibly the tip window itself. But no, this is the window of the control which the tip belongs to, i.e.HWND
of theAssociatedControl
.AssociatedControl
- the control which the tip belongs to.ToolTipSize
- the size of tip window. But from this size component gets onlyWidth
property, and ignoring everything else.Cancel
if we want to cancel tip appearance.
You can check the source for ToolTip.Popup
call.
⚡ ToolTip.Draw
provide very similar arguments, but also some functions to draw (predefined) contents.
It’s call yon can check here in the sources.
ToolTip Class
It’s a mess. It totally relies on the Windows functionality of systems hints. However, I even reached some success in this way.
It would be okay, but I faced with direct usage of ToolTip
class in other controls, and not in a way of OS usage:
ToolStrip, Label, DataGridView, etc.
And, if you want to make it workable you need to copy a lot of .Net internals, especially native imports and marshaling.
Own Implementation
Generally I decide to make it extendable, i.e. add possibility to add support for any other complex controls, and custom too.
Two main API’s for this purpose:
IVisitor
gives possibility to decompose complex controls into parts or items:ListView
➡ListViewItem
;- then
IManager
gives you control for item bounds and tool tip text.
While component have no connection to the form that it is placed on, we need to setup proper form into the BaseForm
property.
Form controls bypass algorithm I copied from original ToolTip
component and narrow it to only needed functionality.
Detailed how-to you can find on github.