C# 如何将鼠标滚轮消息从一个窗口重定向到另一个窗口?

C# 如何将鼠标滚轮消息从一个窗口重定向到另一个窗口?,c#,winforms,imessagefilter,C#,Winforms,Imessagefilter,WM_鼠标滚轮消息通过焦点发送到控件。我的应用程序有一个复杂的控件层次结构,控件包含其他控件,其中一些控件不可见或重叠。我希望鼠标滚轮滚动特定的ScrollableControl 有一个带有捕获WM_鼠标滚轮消息的IMessageFilter实现的答案。这很有效,我看到消息被捕获。我试图通过更改VerticalScroll.value的值,操纵ScrollableControl的VerticalScroll属性来滚动其内容。不幸的是,有一些不良的副作用,如滚动条中的鼠标拇指与Scrollable

WM_鼠标滚轮
消息通过焦点发送到控件。我的应用程序有一个复杂的控件层次结构,控件包含其他控件,其中一些控件不可见或重叠。我希望鼠标滚轮滚动特定的
ScrollableControl

有一个带有捕获
WM_鼠标滚轮
消息的
IMessageFilter
实现的答案。这很有效,我看到消息被捕获。我试图通过更改
VerticalScroll.value
的值,操纵ScrollableControl的
VerticalScroll
属性来滚动其内容。不幸的是,有一些不良的副作用,如滚动条中的鼠标拇指与ScrollableControl的内容不同步。这可能是因为这项工作是在消息泵内部完成的,而不是在事件处理程序中完成的

描述一种将WM_鼠标滚轮消息重新发布到另一个窗口的技术。我想实现一个
IMessageFilter
,它捕获
WM_mouseweel
消息,并将它们转发给指定的收件人

我创建了下面的
IMessageFilter
,尝试这样做。我可以看到转发的消息被我的筛选器捕获,我从筛选器返回
false
,告诉控件处理该消息。目标控件未接收到
onmouseheel
事件

是否可以修改此筛选器以允许使用重定向消息滚动my
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;
    }
}

我只是做了同样的事。以下是我所做的:

    public bool PreFilterMessage(ref Message m)
    {
        if ((WM)m.Msg == WM.MOUSEWHEEL)
        {
            // if mouse is over a certain component, prevent scrolling
            if (comboBoxVendors.Bounds.Contains(PointToClient(Cursor.Position)))
            {
                // return true which says the message is already processed
                return true;
            }


            // which direction did they scroll?
            int delta = 0;
            if ((long)m.WParam >= (long)Int32.MaxValue)
            {
                var wParam = new IntPtr((long)m.WParam << 32 >> 32);
                delta = wParam.ToInt32() >> 16;
            }
            else
            {
                delta = m.WParam.ToInt32() >> 16;
            }

            delta = delta*-1;
            var direction = delta > 0 ? 1 : 0;

            // post message to the control I want scrolled (I am converting the vertical scroll to a horizontal, bu you could just re-send the same message to the control you wanted
            PostMessage(splitContainerWorkArea.Panel2.Handle, Convert.ToInt32(WM.HSCROLL), (IntPtr) direction, IntPtr.Zero);

            // return true to say that I handled the message
            return true;
        }                           

        // message was something other than scroll, so ignore it
        return false;
    }

我只是做了同样的事。以下是我所做的:

    public bool PreFilterMessage(ref Message m)
    {
        if ((WM)m.Msg == WM.MOUSEWHEEL)
        {
            // if mouse is over a certain component, prevent scrolling
            if (comboBoxVendors.Bounds.Contains(PointToClient(Cursor.Position)))
            {
                // return true which says the message is already processed
                return true;
            }


            // which direction did they scroll?
            int delta = 0;
            if ((long)m.WParam >= (long)Int32.MaxValue)
            {
                var wParam = new IntPtr((long)m.WParam << 32 >> 32);
                delta = wParam.ToInt32() >> 16;
            }
            else
            {
                delta = m.WParam.ToInt32() >> 16;
            }

            delta = delta*-1;
            var direction = delta > 0 ? 1 : 0;

            // post message to the control I want scrolled (I am converting the vertical scroll to a horizontal, bu you could just re-send the same message to the control you wanted
            PostMessage(splitContainerWorkArea.Panel2.Handle, Convert.ToInt32(WM.HSCROLL), (IntPtr) direction, IntPtr.Zero);

            // return true to say that I handled the message
            return true;
        }                           

        // message was something other than scroll, so ignore it
        return false;
    }