.net ToolStrip有时对鼠标单击没有响应

.net ToolStrip有时对鼠标单击没有响应,.net,winforms,toolstrip,.net,Winforms,Toolstrip,我有一个.NET2.0WinForms应用程序,主窗体上有一个ToolStrip。有时,ToolStrip图标对第一次鼠标单击没有响应,因此我必须单击图标两次。它只是一个带有几个图标和工具提示文本的标准工具条,我没有做任何特殊的事情。这很常见吗?我在其他开发环境(VB6)中也遇到过这种情况,结果是因为第一次单击被工具栏吸收以获得焦点。或者,换一种说法,工具栏在找到焦点之前不会对点击做出响应。要测试这一点,请尝试在单击按钮之前单击工具栏的空白部分。如果您在单击工具栏后不必再单击按钮两次,那么这可能

我有一个.NET2.0WinForms应用程序,主窗体上有一个ToolStrip。有时,ToolStrip图标对第一次鼠标单击没有响应,因此我必须单击图标两次。它只是一个带有几个图标和工具提示文本的标准工具条,我没有做任何特殊的事情。这很常见吗?

我在其他开发环境(VB6)中也遇到过这种情况,结果是因为第一次单击被工具栏吸收以获得焦点。或者,换一种说法,工具栏在找到焦点之前不会对点击做出响应。要测试这一点,请尝试在单击按钮之前单击工具栏的空白部分。如果您在单击工具栏后不必再单击按钮两次,那么这可能就是问题所在。我想我解决了这个问题(这是几年前的事了,请原谅我的黑客行为)就是在鼠标悬停事件中通过编程将焦点赋予工具栏。

如果应用程序窗口没有焦点,你必须单击ToolStrip按钮两次。第一次单击将焦点设置为窗口,第二次单击将引发单击事件。这是(不幸的)默认行为,也是出于设计。Microsoft Word显示了相同的行为(即使.NET ToolStrip不是同一个控件)。

我以前也遇到过同样的问题,我在中找到了解决方案。其思想是覆盖派生类ToolStripEx中的“WndProc”。该解决方案的核心如下所示:

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;
    }
}

您可以创建从ToolStrip继承的自己的类,并使用自定义属性
点击
打开或关闭行为:

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
公共类ToolStripExtended:继承ToolStrip
私有常量WM_MOUSEACTIVATE作为UInteger=&H21
私用Const MA_激活为UInteger=1
私用Const MA_ActivateAnd Deat As UInteger=2
私有Const MA_noactive As UInteger=3
私用Const MA_NOACTIVATEANDEAT As UInteger=4
Private _点击显示为布尔值=False
公共分新()
MyBase.New()
端接头
''' 
''获取或设置ToolStripEx在其包含表单单击时是否对该项进行单击
''没有输入焦点。
''' 
''' 
''默认值为false,这与基本ToolStrip类提供的行为相同。
''' 
作为布尔值的公共属性ClickThrough()
得到
返回给我。\ u点击完成
结束
设置(值为布尔值)
Me.\u点击=值
端集
端属性
受保护的覆盖子WndProc(ByRef m作为消息)
MyBase.WndProc(m)
如果_clickthroughand also m.Msg=WM_MOUSEACTIVATE and also m.Result=New IntPtr(MA_ACTIVATEANDEAT),则
m、 结果=新IntPtr(MA_激活)
如果结束
端接头
末级

以下是@Doc Brown解决方案的实现:

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;
        }
    }
}

谢谢,无论如何,这似乎不是我的情况。如果我将焦点设置为另一个控件(比如ToolStrip外的一个按钮),然后单击ToolStrip按钮,则会接受该单击。MS Word和.NET ToolStrip按钮之间有一个区别:当Word应用程序没有焦点时,Word中的菜单和符号不会被鼠标光标高亮显示。它们只有在Word具有焦点时才会突出显示。另一方面,.NET ToolStrip即使在应用程序没有焦点的情况下也会高亮显示其按钮,假装鼠标单击会立即激活按钮。这是完美的,比我尝试过的任何替代方法都好。还要确保设计器代码中的
myToolStrip.ClickThrough=true
,否则它无法工作。