将鼠标滚轮事件重定向到未获得焦点的 Windows 窗体控件
MouseWheelRedirector 将鼠标滚轮事件重定向到 Windows Forms 应用程序中鼠标指针下的控件,而不考虑控件是否被点击/聚焦。只需将控件附加到 Redirector,无需额外编码。
引言
在 Windows Forms 应用程序中,鼠标滚轮事件默认会转到具有焦点的控件。因此,用户必须先单击控件才能在其上使用滚轮。在许多情况下,这种行为既令人讨厌又不直观,如果鼠标滚轮可以滚动/缩放/任何 鼠标指针下的控件,应用程序可以提供更好的用户体验。这种行为也被称为鼠标悬停滚动或鼠标悬停缩放。一个经典的例子是类似于 Windows 资源管理器的 TreeView/ListView 组合。
背景
为了在不同的应用程序中实现这种行为,我一遍又一遍地使用 MouseEnter
, MouseLeave
, IMessageFilter
等编写相同的代码。所以我想写一个类,它允许我用一行代码完成它 - 这就是我所想到的。它允许我简单地将任何控件附加到重定向器,并且只要鼠标指针位于其范围内,它将立即开始接收鼠标滚轮事件。
Using the Code
- 将 MouseWheelRedirector.vb 添加到您的 Windows Forms 应用程序项目。
- 开始接收控件的鼠标滚轮事件
- 停止接收该控件的鼠标滚轮事件(除非已聚焦)
- 暂停所有已附加控件的重定向(不分离它们)
- 恢复所有已附加控件的重定向
MouseWheelRedirector.Attach(myControl)
MouseWheelRedirector.Detach(myControl)
MouseWheelRedirector.Active = False
MouseWheelRedirector.Active = True
以下是一些示例代码,展示了该类与 TreeView
和 ListView
的用法。要使用它,只需创建一个新的 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
关注点
此类使用以下技术来完成给定的任务
- 监听控件的
MouseEnter
和MouseLeave
事件,以确定鼠标指针何时位于控件上。 - 实现
IMessageFilter
以捕获应用程序中的WM_MOUSEWHEEL
消息。 - PInvoke Windows API 调用
SendMessage
,将WM_MOUSEWHEEL
消息重定向到控件的句柄。 IMessageFilter
对象实现为MouseWheelRedirector
类的单例,并通过共享成员Attach
,Detach
和Active
进行访问。
限制
正如 herves 在“评论和讨论”部分指出的,如果附加控件有子控件,当鼠标指针位于其中一个子控件上时,重定向器将不起作用:每当鼠标指针碰到子控件时,父控件的 mouse leave 事件将触发,并且父控件将停止接收重定向的鼠标滚轮事件,直到下一次 mouse enter 事件。
历史
- 2011 年 11 月 15 日:在
Detach
函数中添加了一行代码
If instance.currentControl Is control Then instance.currentControl = Nothing