WM_MOUSEWHEEL
сообщения отправляются в элемент управления с фокусом. Мое приложение имеет сложную иерархию управления с элементами управления, содержащими другие элементы управления, некоторые из которых невидимы или перекрываются. Я хотел бы, чтобы колесо мыши прокручивало конкретный ScrollableControl
.Как перенаправить сообщения колесика мыши из одного окна в другое?
This question имеет ответ с помощью IMessageFilter
осуществления, который ловит WM_MOUSEWHEEL
сообщений. Это хорошо работает, и я вижу, что сообщения пойманы. Я попробовал манипулировать свойством ScrollableControl VerticalScroll
, чтобы прокрутить его содержимое, изменив значение VerticalScroll.Value
. К сожалению, есть некоторые нежелательные побочные эффекты, такие как большой палец мыши в полосе прокрутки, который не синхронизируется с содержимым ScrollableControl. Возможно, это потому, что эта работа выполняется внутри насоса сообщений, а не в обработчике событий.
This post описывает технику, в которой сообщения WM_MOUSEWHEEL отправляются в другое окно. Я хотел бы реализовать IMessageFilter
, который ловит сообщения WM_MOUSEWHEEL
и пересылает их назначенному получателю.
Я создаю следующее IMessageFilter
, которое пытается это сделать. Я вижу, что пересылаемое сообщение попадает в мой фильтр, и я возвращаю false
из фильтра, чтобы передать управление для обработки сообщения. Целевой элемент управления не принимает событие OnMouseWheel
.
Можно ли изменить этот фильтр, чтобы можно было прокручивать targetControl
с помощью перенаправленных сообщений?
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;
}
}