We have an old (very old) WinForms application that depended on some 3rd party components that we are no longer allowed to use. One of those components was used to display tooltips on individual nodes in a normal TreeView. Nothing very fancy, but special enough that we cannot simply use the built-in ToolTipText of the TreeNode objects.
I have implemented customized tooltips before, and thought that this would be a simple thing, but I am stuck.
I added a ToolTip control with OwnerDraw = true, IsBalloon = false, and Active = true, and assigned event handlers for the Popup and Draw events.
Since a TreeNode is not a Control, the tooltip is not displayed automatically when hovering the mouse cursor over it. So I have code in the MouseMove and MouseLeave events for the TreeView that shows/hides the node item tooltip by invoking the Show() and Hide() methods of the ToolTip control.
All these parts work just fine (which is why I have not included any code), but the result is still worthless: The tooltip is either too small for the text it shows (making the tooltip useless), or too large (which just looks silly). And I am not talking about margins here - the difference to what the size should be is pretty big. The box size really needs to be set specifically for each node.
The direct reason for the problem is that the Popup event (which determines the size of the tooltip to display) is not fired properly. My guess is that this behavior is connected to the fact that the "source" Control of the tooltip does not change - it is always the TreeView. But even it that is correct, i have no idea of how to get around it.
We have lowered our ambitions for how "pretty" the tooltips need to be, and is down to this:
When hovering the mouse cursor over a tree node, we can get the whole tooltip text as a simple C# string - multi-line with 1 to 10 or so lines, separated by LF.
If we could just change the tooltip font to Consolas (fixed-width), showing that string as tooltip for the node would be quite good enough.
Any help would be greatly appreciated.
UPDATE
The accepted answer from @Olivier works perfectly, and does exactly what I asked for. The only problem is that this is pretty much exactly how I was already doing it :-/
The only difference is that 1) I trigger the opening of the tooltip in the MouseMove event (more suitable than NodeMouseHover in relation to other functionality in my case), and 2) I use a Forms.Timer to delay the tooltip a bit (better for the users on this form).
Neither of those differences should affect the result, but just to make sure, I removed the timer, and invoked ToolTip.Show() (directly) from the NodeMouseHover event. It made no difference - the Popup event still do not fire.
As mentioned in my comment to the answer, I had already tried Olivier's code at home, and it worked just fine. But it hit me that I was unsure of which .NET variant I had used. So I created two new identical projects (using Olivier's code): One for .NET 8 (which is what we use for all new projects, and probably what I used at home), and one for .NET Framework 4.8, which is what we are stuck with for the application that I am talking about.
The result is that it works fine with .NET 8, but not with .NET Framework 4.8 (the Popup event is not fired) :-(
As far as I can tell from the documentation, this should work in the same way for .NET Framework and .NET. Perhaps there are other factors unknown to me.
In any case, now that I know that it cannot be done this way (migrating to .NET 8 is not an option for this application), I will find a different way of doing it.
Than you!
SOLUTION
This answer from @shingo to the follow-up question I mentioned above, explains the cause of the problem, and suggests three solutions. Solution 2 (a fix for the actual problem by subclassing the TreeView) is just what I needed.
You may also want to look at the answer from @dr.null. Even if it is not the accepted anser, it contains a lot of relevant stuff.
I did a quick test as follows (for the sake of simplicity I just used the nodes' text as tooltip):
public partial class FormTreeNodeToolTip : Form
{
private static readonly Font _font = new Font("Consolas", 16, FontStyle.Regular);
private TreeNode _currentNode;
public FormTreeNodeToolTip()
{
InitializeComponent();
}
private void ToolTip1_Draw(object sender, DrawToolTipEventArgs e)
{
e.Graphics.Clear(Color.LightYellow);
e.Graphics.DrawString(e.ToolTipText, _font, Brushes.Blue, e.Bounds);
}
private void TreeView1_NodeMouseHover(object sender, TreeNodeMouseHoverEventArgs e)
{
_currentNode = e.Node;
Point cursor = treeView1.PointToClient(Cursor.Position);
toolTip1.Show(e.Node.Text, treeView1, cursor.X + 20, cursor.Y + 20, 800);
}
private void ToolTip1_Popup(object sender, PopupEventArgs e)
{
e.ToolTipSize = TextRenderer.MeasureText(_currentNode.Text, _font);
}
private void TreeView1_MouseMove(object sender, MouseEventArgs e)
{
if (treeView1.GetNodeAt(e.Location) != _currentNode) {
_currentNode = null;
toolTip1.Hide(treeView1);
}
}
private void TreeView1_MouseLeave(object sender, EventArgs e)
{
toolTip1.Hide(treeView1);
}
}
This works well and the size of the tooltips matches my expectations.
Note: It would still be helpful if you showed us your code, so that we could see what causes the problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With