Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Redirect Mouse Wheel Events to Unfocused Windows Forms Controls

4.88/5 (7 votes)
16 Nov 2011CPOL2 min read 69K   2.1K  
MouseWheelRedirector redirects mouse wheel events to the control under the mouse pointer in Windows Forms applications, regardless of the control being clicked/focused. Just attach the control to the Redirector, no additional coding is required.

Introduction

In a Windows Forms application, the mouse wheel events will go by default to the control that has focus. So the user has to click the control before using the wheel on it. In many cases, this behaviour is annoying and counterintuitive and the application could provide a much better user experience if the mouse wheel would scroll/zoom/whatever the control under the mouse pointer. This behaviour is also known as mouse over scrolling or mouse over zooming. A classic example for this is a TreeView/ListView combination similar to a Windows Explorer.

Background

To implement this behaviour in different applications, I wrote the same code again and again using MouseEnter, MouseLeave, IMessageFilter, etc. So I did want to write a class that would allow me to do it in one single line of code - and this is what I came up with. It allows me to simply attach any control to the redirector and it will immediately start receiving the mouse wheel events whenever the mouse pointer is inside its bounds.

Using the Code

  1. Add MouseWheelRedirector.vb to your Windows Forms Application project.
  2. To start receiving mouse wheel events for a control:
  3. VB
    MouseWheelRedirector.Attach(myControl)
  4. To stop receiving mouse wheel events for that control (unless focused):
  5. VB
    MouseWheelRedirector.Detach(myControl)
  6. To suspend redirection for all attached controls (without detaching them):
  7. VB
    MouseWheelRedirector.Active = False
  8. To resume redirection for all attached controls:
  9. VB
    MouseWheelRedirector.Active = True

Here is some example code showing the usage of the class with a TreeView and a ListView. To use it, just create a new Windows Application and drop the following code into the code window for Form1:

VB
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

Points of Interest

This class uses the following techniques for the given task:

  • Listen to the control's MouseEnter and MouseLeave events to determine when the mouse pointer is over the control.
  • Implement IMessageFilter to catch WM_MOUSEWHEEL messages in the application.
  • PInvoke the Windows API call SendMessage redirecting the WM_MOUSEWHEEL message to the control's handle.
  • The IMessageFilter object is implemented as a singleton of the MouseWheelRedirector class and accessed by the shared members Attach, Detach, and Active.

Limitations

As herves pointed out in the Comments and Discussions section, if an attached control has child controls, the redirector won't work when the mouse pointer is over one of the child controls: whenever the mouse pointer hits the child control, the parent control's mouse leave event will fire and the parent control will stop receiving redirected mouse wheel events until the next mouse enter event.

History

  • November 15, 2011: Added one line of code to the Detach function:
  • VB
    If instance.currentControl Is control Then instance.currentControl = Nothing
  • November 16, 2011: Added the Limitations section to the article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)