65.9K
CodeProject 正在变化。 阅读更多。
Home

将鼠标滚轮事件重定向到未获得焦点的 Windows 窗体控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (7投票s)

2011 年 11 月 8 日

CPOL

2分钟阅读

viewsIcon

70397

downloadIcon

2106

MouseWheelRedirector 将鼠标滚轮事件重定向到 Windows Forms 应用程序中鼠标指针下的控件,而不考虑控件是否被点击/聚焦。只需将控件附加到 Redirector,无需额外编码。

引言

在 Windows Forms 应用程序中,鼠标滚轮事件默认会转到具有焦点的控件。因此,用户必须先单击控件才能在其上使用滚轮。在许多情况下,这种行为既令人讨厌又不直观,如果鼠标滚轮可以滚动/缩放/任何 鼠标指针下的控件,应用程序可以提供更好的用户体验。这种行为也被称为鼠标悬停滚动或鼠标悬停缩放。一个经典的例子是类似于 Windows 资源管理器的 TreeView/ListView 组合。

背景

为了在不同的应用程序中实现这种行为,我一遍又一遍地使用 MouseEnter, MouseLeave, IMessageFilter 等编写相同的代码。所以我想写一个类,它允许我用一行代码完成它 - 这就是我所想到的。它允许我简单地将任何控件附加到重定向器,并且只要鼠标指针位于其范围内,它将立即开始接收鼠标滚轮事件。

Using the Code

  1. MouseWheelRedirector.vb 添加到您的 Windows Forms 应用程序项目。
  2. 开始接收控件的鼠标滚轮事件
  3. MouseWheelRedirector.Attach(myControl)
  4. 停止接收该控件的鼠标滚轮事件(除非已聚焦)
  5. MouseWheelRedirector.Detach(myControl)
  6. 暂停所有已附加控件的重定向(不分离它们)
  7. MouseWheelRedirector.Active = False
  8. 恢复所有已附加控件的重定向
  9. MouseWheelRedirector.Active = True

以下是一些示例代码,展示了该类与 TreeViewListView 的用法。要使用它,只需创建一个新的 Windows 应用程序并将以下代码放入 Form1 的代码窗口中

Option Explicit On
Option Strict On
Option Infer On

Imports System.Windows.Forms

Public Class Form1

    Private Sub Form1_Load(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles Me.Load

        Dim tools = New ToolStrip
        tools.Items.Add(New ToolStripButton("Suspend MouseWheelRedirector", _
                    Nothing, AddressOf SuspendRedirector))
        tools.Items.Add(New ToolStripButton("Resume MouseWheelRedirector", _
                    Nothing, AddressOf ResumeRedirector))

        Dim split = New SplitContainer
        split.Dock = DockStyle.Fill

        Dim tree = New TreeView
        tree.Dock = DockStyle.Fill

        Dim list = New ListView
        list.Dock = DockStyle.Fill
        list.View = View.List

        Me.Height = 300
        Me.Width = 800

        split.Panel1.Controls.Add(tree)
        split.Panel2.Controls.Add(list)

        Me.Controls.Add(split)
        Me.Controls.Add(tools)

        For i = 0 To 199
            tree.Nodes.Add("Tree View Node " & i)
            list.Items.Add("List View Item " & i)
        Next

        tree.ExpandAll()

        MouseWheelRedirector.Attach(tree)
        MouseWheelRedirector.Attach(list)
    End Sub

    Private Sub SuspendRedirector(ByVal sender As Object, ByVal e As System.EventArgs)
        MouseWheelRedirector.Active = False
    End Sub

    Private Sub ResumeRedirector(ByVal sender As Object, ByVal e As System.EventArgs)
        MouseWheelRedirector.Active = True
    End Sub

End Class

关注点

此类使用以下技术来完成给定的任务

  • 监听控件的 MouseEnterMouseLeave 事件,以确定鼠标指针何时位于控件上。
  • 实现 IMessageFilter 以捕获应用程序中的 WM_MOUSEWHEEL 消息。
  • PInvoke Windows API 调用 SendMessage,将 WM_MOUSEWHEEL 消息重定向到控件的句柄。
  • IMessageFilter 对象实现为 MouseWheelRedirector 类的单例,并通过共享成员 Attach, DetachActive 进行访问。

限制

正如 herves 在“评论和讨论”部分指出的,如果附加控件有子控件,当鼠标指针位于其中一个子控件上时,重定向器将不起作用:每当鼠标指针碰到子控件时,父控件的 mouse leave 事件将触发,并且父控件将停止接收重定向的鼠标滚轮事件,直到下一次 mouse enter 事件。

历史

  • 2011 年 11 月 15 日:在 Detach 函数中添加了一行代码
  • If instance.currentControl Is control Then instance.currentControl = Nothing
  • 2011 年 11 月 16 日:向文章中添加了“限制”部分。
© . All rights reserved.