WM_MOUSEWHEEL
Nachrichten werden mit dem Fokus an die Steuerung gesendet. Meine Anwendung hat eine komplexe Steuerungshierarchie mit Steuerelementen, die andere Steuerelemente enthalten, von denen einige unsichtbar oder überlappend sind. Ich möchte mit dem Mausrad eine bestimmte ScrollableControl
scrollen.Wie leite ich Mausradmeldungen von einem Fenster zum anderen um?
This question hat eine Antwort mit einer IMessageFilter
Implementierung, die Nachrichten WM_MOUSEWHEEL
fängt. Das funktioniert gut und ich sehe die Nachrichten gefangen werden. Ich versuchte ScrollableControls VerticalScroll
Eigenschaft zu manipulieren, um seinen Inhalt zu scrollen, indem ich den Wert VerticalScroll.Value
änderte. Leider gibt es einige unerwünschte Nebeneffekte wie der Mausdaum in der Bildlaufleiste, der mit dem Inhalt des ScrollableControls nicht synchronisiert wird. Vielleicht liegt das daran, dass diese Arbeit innerhalb der Nachrichtenpumpe statt in einem Ereignishandler ausgeführt wird.
This post beschreibt eine Technik, bei der WM_MOUSEWHEEL-Nachrichten in ein anderes Fenster verschoben werden. Ich möchte ein IMessageFilter
implementieren, das WM_MOUSEWHEEL
Nachrichten abfängt, und sie an einen bestimmten Empfänger weiterleitet.
Ich erstelle die folgenden IMessageFilter
, die dies versucht. Ich kann sehen, dass die weitergeleitete Nachricht von meinem Filter abgefangen wird, und ich gebe false
aus dem Filter zurück, um dem Steuerelement mitzuteilen, dass es die Nachricht verarbeiten soll. Das Zielsteuerelement erhält kein OnMouseWheel
Ereignis.
Kann dieser Filter geändert werden, damit meine targetControl
mit umgeleiteten Nachrichten gescrollt werden kann?
public static class MouseWheelMessageRedirector
{
public static void Add(Control rootControl, ScrollableControl targetControl)
{
var filter = new MouseWheelMessageFilter(rootControl, targetControl);
Application.AddMessageFilter(filter);
rootControl.Disposed += (sender, args) => Application.RemoveMessageFilter(filter);
targetControl.MouseWheel += (sender, args) =>
{
// ... this code never executes
System.Diagnostics.Trace.WriteLine("WHEEL ON TARGET");
};
}
private class MouseWheelMessageFilter : IMessageFilter
{
const int WM_MOUSEWHEEL = 0x020A;
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
public MouseWheelMessageFilter(Control rootControl, ScrollableControl targetControl)
{
_rootControl = rootControl;
_targetControl = targetControl;
_targetWindowHandle = _targetControl.Handle;
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg != WM_MOUSEWHEEL)
return false;
if (m.HWnd == _targetWindowHandle)
return false;
// ... get the control that the mouse is over
// ... determine if this is a control that we want to handle the message for
// ... (omitted)
PostMessage(_targetWindowHandle, m.Msg, m.WParam, m.LParam);
return true;
}
private Control _rootControl;
private ScrollableControl _targetControl;
private IntPtr _targetWindowHandle;
}
}