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

本文关键字:窗口 一个 重定向 另一个 鼠标 消息 | 更新日期: 2024-09-22 19:56:14

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

这个问题通过捕获WM_MOUSEWHEEL消息的IMessageFilter实现得到了答案。这很有效,我看到消息被捕获了。我尝试通过更改VerticalScroll.Value的值来操纵ScrollableControl的VerticalScroll属性以滚动其内容。不幸的是,还有一些不希望的副作用,比如滚动条中的鼠标拇指与ScrollableControl的内容不同步。也许这是因为这项工作是在消息泵中而不是在事件处理程序中完成的。

这篇文章描述了一种将WM_MOUSEWEEL消息转发到另一个窗口的技术。我想实现一个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;
    }
}

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

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

    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;
    }

此外,我使用了PInvoke.net中的windows消息枚举:http://www.pinvoke.net/default.aspx/Enums.WindowsMessages

最后,当您关闭表单时,或者当您不再需要处理消息时,请确保删除消息过滤器:

Application.RemoveMessageFilter(thisForm)