在许多应用程序中,用户在使用鼠标滚轮时,需要先点击控件才能触发滚动或其他操作。这种默认行为有时会导致用户体验不佳,如果应用程序能够实现鼠标指针在控件上时自动响应滚轮事件,将大大提高用户体验。这种功能通常被称为鼠标悬停滚动或鼠标悬停缩放。一个典型的例子是在Windows资源管理器中组合使用TreeView和ListView。
为了在不同的应用程序中实现这种功能,不得不一次又一次地编写相同的代码,使用MouseEnter、MouseLeave、IMessageFilter等。因此,创建了一个类,它允许通过一行代码实现这个功能。这个类可以简单地将任何控件附加到重定向器上,并且当鼠标指针在其边界内时,它将立即开始接收鼠标滚轮事件。
将MouseWheelRedirector.vb添加到Windows Forms应用程序项目中。
要开始为控件接收鼠标滚轮事件,请使用以下代码:
Dim myControl As New Control()
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 As New ToolStrip()
tools.Items.Add(New ToolStripButton("Suspend MouseWheelRedirector", Nothing, AddressOf SuspendRedirector))
tools.Items.Add(New ToolStripButton("Resume MouseWheelRedirector", Nothing, AddressOf ResumeRedirector))
Dim split As New SplitContainer()
split.Dock = DockStyle.Fill
Dim tree As New TreeView()
tree.Dock = DockStyle.Fill
Dim list As 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
这个类使用了以下技术来完成给定的任务:
IMessageFilter对象作为MouseWheelRedirector类的单例实现,并通过共享成员Attach、Detach和Active进行访问。
正如在评论和讨论部分所指出的,如果附加的控件有子控件,当鼠标指针在子控件上时,重定向器将无法工作:每当鼠标指针击中子控件时,父控件的鼠标离开事件将触发,父控件将停止接收重定向的鼠标滚轮事件,直到下一个鼠标进入事件。
If instance.currentControl Is control Then
instance.currentControl = Nothing
End If