8
votes

ToolStripItems show Active highlighting when you mouse over them, even if the form they are in is not in focus. They do not, however, show their tooltips, unless the form is focused. I have seen the ToolStrip 'click-though' hack. Anyone know how to make a ToolStripButton show its tooltip when its parent form is not in focus?

Thanks!

4
Why do you want to do this? The bug is rather being the active tracking when the form is not focused.OregonGhost
@OregonGhost - I created a floating / always-on-top toolbar and I wanted tooltips to show on mouseover even when other applications were active.foson

4 Answers

6
votes

The problem is that the ToolStrip "controls" like ToolStripButton or ToolStripDropDownButton don't inherit from Control. For now I addressed the problem by focusing the ToolStrip whenever a user hovers over a button. The button's MouseHover event is fired too late -- after the "show tooltip" code would have been run, so I extended the ToolStripDropDownButton class and used my new button. This method should work for any of the other button-like classes inheriting from ToolStripItem

public class ToolStripDropDownEx : ToolStripDropDownButton
{
    public ToolStripDropDownEx(string text)
    {
    }

    protected override void OnMouseHover(EventArgs e)
    {
        if (this.Parent != null)
            Parent.Focus();
        base.OnMouseHover(e);
    } 
}
3
votes

Perhaps one of the two approaches in this code will kick you off in the right direction...

public Form1()
{
    InitializeComponent();

    tooltip = new ToolTip();
    tooltip.ShowAlways = true;
}

private ToolTip tooltip;
private void toolStripButton_MouseHover(object sender, EventArgs e)
{
    if (!this.Focused)
    {
        ToolStripItem tsi = (ToolStripItem)sender;
        tooltip.SetToolTip(toolStrip1, tsi.AutoToolTip ? tsi.ToolTipText : tsi.Text);
        /*tooltip.Show(tsi.AutoToolTip ? tsi.ToolTipText : tsi.Text, this, 
            new Point(toolStrip1.Left, toolStrip1.Bottom));*/
    }
}

private void toolStripButton_MouseLeave(object sender, EventArgs e)
{
    tooltip.RemoveAll();
}

The problem with the first is you can't set it to the button directly, it doesn't inherit from Control, and the tooltip won't show up unless you're over the strip but not over a button.

The problem with the second (commented out way) is it doesn't display at all. Not quite sure why, but maybe you can debug it out.

2
votes

i tried a few things and found this to be the simplest

when i create the toolstripbutton items i added an event handler to its hover event:

private sub SomeCodeSnippet()

    Me.tooltipMain.ShowAlways = True

    Dim tsi As New ToolStripButton(String.Empty, myImage)
    tsi.ToolTipText = "my tool tip text"
    toolstripMain.Add(tsi)

    AddHandler tsi.MouseHover, AddressOf ToolStripItem_MouseHover

end sub

then the event handler:

Private Sub ToolStripItem_MouseHover(ByVal sender As Object, ByVal e As System.EventArgs)

    If TypeOf sender Is ToolStripButton Then
        Me.tooltipMain.SetToolTip(Me.toolstripMain, CType(sender, ToolStripButton).ToolTipText)
    End If

End Sub

this works really nicely, although i do notice a tiny initial delay when you hover over the toolstrip for the 1st time

1
votes

I was trying to do the same thing and determined it was going to be pretty challenging and not worth it. The reason is that internally, the .NET code is specifically designed to only show the tooltip if the window is active - they are checking this at a Win32 level so its going to be hard to fake the code out.

Here is the code snippet in ToolTip.cs that checks "GetActiveWindow()" and returns false. You can see the comment in the code "ToolTips should be shown only on active Windows."

By the way, you can see all the source code for the .NET BCL with Visual Studio 2008, here are the instructions I used:

http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx

// refer VsWhidbey 498263: ToolTips should be shown only on active Windows.
private bool IsWindowActive(IWin32Window window)
{ 
    Control windowControl = window as Control;
    // We want to enter in the IF block only if ShowParams does not return SW_SHOWNOACTIVATE. 
    // for ToolStripDropDown ShowParams returns SW_SHOWNOACTIVATE, in which case we DONT want to check IsWindowActive and hence return true. 
    if ((windowControl.ShowParams & 0xF) != NativeMethods.SW_SHOWNOACTIVATE)
    { 
        IntPtr hWnd = UnsafeNativeMethods.GetActiveWindow();
        IntPtr rootHwnd =UnsafeNativeMethods.GetAncestor(new HandleRef(window, window.Handle), NativeMethods.GA_ROOT);
        if (hWnd != rootHwnd)
        { 
            TipInfo tt = (TipInfo)tools[windowControl];
            if (tt != null && (tt.TipType & TipInfo.Type.SemiAbsolute) != 0) 
            { 
                tools.Remove(windowControl);
                DestroyRegion(windowControl); 
            }
            return false;
        }
    } 
    return true;
}