ToolStrip有时候无法响应鼠标点击。

12

我有一个.NET 2.0 WinForms应用程序,在我的主窗体上有一个ToolStrip。有时,ToolStrip图标不会响应第一次鼠标单击,所以我必须点击两次图标。这只是一个带有几个图标和工具提示文本的标准ToolStrip,我没有做任何特殊处理。这种情况常见吗?

5个回答

27

我之前也遇到了同样的问题,并在Rick Brewster的博客中找到了解决方案,参考了此链接。这个解决方案的核心是在派生类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;
    }
}

这太完美了,比我尝试过的任何替代方案都要好。 - user169771
同时确保在设计器代码中设置 myToolStrip.ClickThrough = true,否则它将无法正常工作。 - SharpC

4
你可以创建一个继承自ToolStrip的类,并使用自定义属性ClickThrough来切换行为的开关:
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

3

我在其他开发环境(VB6)中遇到过这个问题,原因是第一次点击被工具栏吸收以获取焦点。换句话说,在工具栏获得焦点之前,工具栏不会响应单击事件。要测试这一点,请在单击按钮之前单击工具栏的空白部分。如果在单击工具栏后再次单击按钮,则可能存在该问题。我认为解决方法(这是多年前的事情,所以请原谅我使用的技巧)是在MouseOver事件中编程地将焦点赋予工具栏。


谢谢,不过似乎这并不是我的情况。如果我将焦点设置到另一个控件(比如在ToolStrip之外的一个按钮)上,然后再单击ToolStrip按钮,那么单击操作就会被接受。 - user20353

0

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


5
MS Word和.NET ToolStrip按钮之间有区别:当Word应用程序没有焦点时,鼠标光标不会高亮显示Word中的菜单和符号。只有当Word有焦点时,它们才会被高亮显示。另一方面,.NET ToolStrip即使应用程序没有焦点,也会突出显示其按钮,假装鼠标单击会立即激活该按钮。 - Doc Brown

0
这是@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;
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接