I suggest to:
- declare your ToolTip Form in Program.cs
- add static Methods to show and hide it
Of course you can use a dedicated class that exposes static methods to handle your ToolTip Form
You can then reach your ToolTip Form from anywhere in your application, just call ShowToolTip()
and HideToolTip()
when the Mouse pointer enters or leaves a specific Control: the bounds of this Control, translated to Screen coordinates, are used as reference to position the ToolTip.
Here, I'm using a simplified method to determine whether the ToolTip should be shown to the right or left and to the top or bottom of the reference Control:
- if the reference Control is positioned to the left half of the screen, then the left potion of the Form is:
ToolTip.Left = [ref Control].Left
- otherwise,
ToolTip.Left = [ref Control].Right - ToolTip-Width
- the same logic applies to the top position of the ToolTip
Adjust this simple calculation to position your ToolTip Form using a different logic, if needed.
▶ There's no need to dispose of the ToolTip Form: it's automatically disposed of when the Form instance passed to Application.Run()
is closed.
Note: If the Application is not DpiAware and the Screen where the Application's Windows are shown is scaled, any measure relative to either the Screen or the Windows/Forms may be virtualized, so you receive wrong results and any calculation will be off.
See the notes here:
Using SetWindowPos with multiple monitors
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;
public static frmToolTip tooltip = null;
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
tooltip = new frmToolTip();
Application.Run(new SomeForm());
}
public async static Task ShowToolTip(Control control, string title) {
await Task.Delay(400);
if (tooltip.Visible) return;
Rectangle refBounds = control.RectangleToScreen(control.ClientRectangle);
if (!refBounds.Contains(Cursor.Position)) {
HideToolTip();
}
else {
var screen = Screen.GetBounds(control);
var leftPos = refBounds.Left <= screen.Width / 2 ? refBounds.Left : refBounds.Right - tooltip.Width;
var topPos = refBounds.Top <= screen.Height / 2 ? refBounds.Bottom + 2: refBounds.Top - tooltip.Height - 2;
tooltip.Location = new Point(leftPos, topPos);
tooltip.Text = title;
tooltip.Show(control.FindForm());
}
}
public static void HideToolTip() => tooltip.Hide();
In any Form, use a Control's MouseEnter
and MouseLeave
events to show/hide your ToolTip.
Note: I'm using Task.Delay()
to delay the presentation of the ToolTip, so it doesn't show up if you briefly move the Mouse Pointer over the Control that shows it.
It also verifies whether the Form ToolTip is already shown (you cannot show a Form twice) or the Mouse Pointer has moved outside the bounds of the reference Control in the meanwhile (the ToolTip is not shown in this case).
Change this behavior as required.
- In
ShowToolTip()
, I'm passing a string, meant to be used as the Title of the ToolTip. It's just an example, to show that you may pass any other parameter to this method (a class object, maybe) to setup the ToolTip Form in a custom way, different based on the caller requirements.
using System.Threading.Tasks;
public partial class SomeForm : Form
{
// [...]
private async void SomeControl_MouseEnter(object sender, EventArgs e)
{
await Program.ShowToolTip(sender as Control, "Some Title Text");
}
private void SomeControl_MouseLeave(object sender, EventArgs e)
{
Program.HideToolTip();
}
}