【问题标题】:How do I redirect mouse wheel messages from one window to another?如何将鼠标滚轮消息从一个窗口重定向到另一个窗口?
【发布时间】:2016-04-15 15:13:27
【问题描述】:

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

This question 有一个IMessageFilter 实现的答案,它捕获WM_MOUSEWHEEL 消息。这很好用,我看到消息被捕获。我尝试通过更改VerticalScroll.Value 的值来操作ScrollableControl 的VerticalScroll 属性来滚动其内容。不幸的是,有一些不良副作用,例如滚动条中的鼠标拇指与 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;
    }
}

【问题讨论】:

    标签: c# winforms imessagefilter


    【解决方案1】:

    我只是做了同样的事情。这是我所做的:

        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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多