I have a .NET 2.0 WinForms application with a ToolStrip on my main form. Sometimes, the ToolStrip icons don't respond to the first mouse click, so I have to click the icon twice. It's just a standard ToolStrip with several icons and tooltip texts, I don't do anything special. Is this common?
5 Answers
I had the same problem some time ago, and I found a solution in Rick Brewster's blog, referencing this link. The idea is to overwrite 'WndProc' in a derived class ToolStripEx. The core of that solution looks like this:
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == NativeConstants.WM_MOUSEACTIVATE &&
m.Result == (IntPtr)NativeConstants.MA_ACTIVATEANDEAT)
{
m.Result = (IntPtr)NativeConstants.MA_ACTIVATE;
}
}

- 19,739
- 7
- 52
- 88
-
This is perfect, better than any of the alternatives I've tried. – user169771 Oct 31 '16 at 03:06
-
Also ensure `myToolStrip.ClickThrough = true` in the designer code otherwise it doesn't work. – SharpC May 10 '19 at 14:41
You can create your own class that inherits from the ToolStrip and use a custom property ClickThrough
to switch the behaviour on or off:
Public Class ToolStripExtended : Inherits ToolStrip
Private Const WM_MOUSEACTIVATE As UInteger = &H21
Private Const MA_ACTIVATE As UInteger = 1
Private Const MA_ACTIVATEANDEAT As UInteger = 2
Private Const MA_NOACTIVATE As UInteger = 3
Private Const MA_NOACTIVATEANDEAT As UInteger = 4
Private _clickThrough As Boolean = False
Public Sub New()
MyBase.New()
End Sub
''' <summary>
''' Gets or sets whether the ToolStripEx honours item clicks when its containing form does
''' not have input focus.
''' </summary>
''' <remarks>
''' Default value is false, which is the same behaviour provided by the base ToolStrip class.
''' </remarks>
Public Property ClickThrough() As Boolean
Get
Return Me._clickThrough
End Get
Set(value As Boolean)
Me._clickThrough = value
End Set
End Property
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If _clickThrough AndAlso m.Msg = WM_MOUSEACTIVATE AndAlso m.Result = New IntPtr(MA_ACTIVATEANDEAT) Then
m.Result = New IntPtr(MA_ACTIVATE)
End If
End Sub
End Class

- 26,994
- 10
- 93
- 143
I've had that in other dev environments (VB6), and it turned out to be because the first click was being absorbed by the toolbar to acquire the focus. Or, to put it another way, the toolbar wouldn't respond to a click until it had the focus. To test this, try clicking on an empty part of the toolbar before you click on the button. If you never have to click twice on the button after you've clicked on the toolbar then that might be the problem. I think they I got around it (and this was years ago, so please excuse the hack) was to programatically give the focus to the toolbar in the MouseOver event.

- 8,126
- 3
- 29
- 36
-
Thanks, anyway it seems that this is not my case. If I set focus to another control (let's say a button outside the ToolStrip) and then click on a ToolStrip button, the click is accepted. – user20353 Jan 23 '09 at 11:40
If the application window hasn’t got the focus, you have to click the ToolStrip button twice. The first click sets the focus to the window, the second raises the click event. This is (unfortunately) the default behaviour and it’s by design. Microsoft Word shows the same behaviour (even though the .NET ToolStrip is not the same control).
-
5There is a difference between MS Word and the .NET ToolStrip buttons: when the Word application does not have the focus, the menus and symbols in Word are not highlighted by the mouse cursor. They are only highlighted when Word has the focus. On the other hand, the .NET ToolStrip highlights its buttons even when the application does not have the focus, pretendings that a mouse click would activate the button immediately. – Doc Brown Dec 12 '09 at 13:32
Here is the implementation for @Doc Brown's solution:
public class ToolStripX : ToolStrip
{
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_ACTIVATEANDEAT = 2;
private const int MA_ACTIVATE = 1;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_MOUSEACTIVATE &&
m.Result == (IntPtr)MA_ACTIVATEANDEAT)
{
m.Result = (IntPtr)MA_ACTIVATE;
}
}
}

- 1,325
- 11
- 17