How do I receive the MouseWheel event when mouse pointer is not in the window?

1.3k views Asked by At

I noticed that my MouseWheel event handler is only executed when the mouse pointer is in the window. I want it to run the handler even when the pointer is outside the window.

I only have one window in my program and its XAML is structured as below:

<Window ...
 MouseWheel = "Window_MouseWheel">
....
</Window>
1

There are 1 answers

2
Peter Duniho On

In order to receive mouse events when the cursor leaves the window, the window needs to "capture" the mouse. It does this by passing itself to the Mouse.Capture() method.

Note that if your program window loses activation (i.e. the user task-switches to some other program), it will lose the mouse capture. If you want to automatically track the mouse wheel again when the window is later reactivated by the user, you'll need to handle that specifically (i.e. handle the Activated event).

Finally note that with mouse capture enabled, the normal interaction with the window via the mouse doesn't work, nor will Alt-F4. You will need to provide the user with some mechanism for additionally interacting with the program (e.g. handle key events).

Below is a simple example program that shows the basic idea:

XAML:

<Window x:Class="TestSO30866523CaptureMouseWheel.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:TestSO30866523CaptureMouseWheel"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Activated="Window_Activated"
        KeyDown="Window_KeyDown"
        MouseWheel="Window_MouseWheel"
        Title="MainWindow" Height="350" Width="525">
  <StackPanel x:Name="stackPanel1">
    <TextBlock Text="The window cannot be closed while mouse is captured."/>
    <TextBlock Text="Press Escape to stop capture. Press Return to resume capture."/>
    <TextBlock Text="{Binding Value, StringFormat=Value: {0}}"/>
    <TextBlock Text="{Binding MouseCaptured, StringFormat=Mouse is captured: {0}}"/>
  </StackPanel>
</Window>

C#:

public partial class MainWindow : Window
{
    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
        "Value", typeof(int), typeof(MainWindow), new PropertyMetadata(0));
    public static readonly DependencyProperty MouseCapturedProperty = DependencyProperty.Register(
        "MouseCaptured", typeof(bool), typeof(MainWindow));

    public int Value
    {
        get { return (int)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    public bool MouseCaptured
    {
        get { return (bool)GetValue(MouseCapturedProperty); }
        set { SetValue(MouseCapturedProperty, value); }
    }

    private readonly IInputElement _captureElement;

    public MainWindow()
    {
        InitializeComponent();

        _captureElement = this;

        Mouse.AddGotMouseCaptureHandler((DependencyObject)_captureElement, stackPanel1_GotLostMouseCapture);
        Mouse.AddLostMouseCaptureHandler((DependencyObject)_captureElement, stackPanel1_GotLostMouseCapture);
        Mouse.Capture(_captureElement);
        MouseCaptured = Mouse.Captured != null;
    }

    private void stackPanel1_GotLostMouseCapture(object sender, MouseEventArgs e)
    {
        MouseCaptured = Mouse.Captured != null;
    }

    private void Window_MouseWheel(object sender, MouseWheelEventArgs e)
    {
        Value += e.Delta;
    }

    private void Window_Activated(object sender, EventArgs e)
    {
        Mouse.Capture(_captureElement);
    }

    private void Window_KeyDown(object sender, KeyEventArgs e)
    {
        switch (e.Key)
        {
        case Key.Escape:
            Mouse.Capture(null);
            break;
        case Key.Return:
            Mouse.Capture(_captureElement);
            break;
        }
    }
}

When the mouse is captured, the window will respond to mouse wheel events regardless of where the cursor is placed. When the mouse is not captured, it responds to the mouse wheel events only when the cursor is over the window.