鼠标滚轮事件与悬停控制工作(Mouse wheel event to work with hover

2019-07-29 22:10发布

在我的C#3.5的Windows窗体应用程序,我有几个SplitContainers。 有每个(码头填充)内的列表控件。 当焦点在这些控件之一,我移动鼠标滚轮,列表中,这是现在的重点,滚动。

我的任务是滚动列表,目前由鼠标,而不是该选择一个徘徊。 是否有可能在Windows窗体? 如果没有,是否有可能与PInvoke的?

Answer 1:

它看起来像您可以使用IMessageFilter和PInvoke的处理这个问题。 在VB中的一个例子,可以发现重定向鼠标滚轮事件到没有重点的Windows窗体控件 。 你应该能够很容易地将此​​转换为C#。

兴趣点

这个类使用给定的任务以下技术:

  • 听控制的的MouseEnter和鼠标离开事件,以确定当鼠标指针悬停在控制。
  • 实施IMessageFilter赶上WM_MOUSEWHEEL对应用消息。
  • 的PInvoke Windows API调用SendMessage函数重定向WM_MOUSEWHEEL消息控件的句柄。
  • 所述IMessageFilter对象被实现为MouseWheelRedirector类的单一和访问由共享成员连接,分离,和激活。

使用一个VB.NET到C#转换器 ,这是你到底是什么了:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;

using System.Windows.Forms;
using System.Runtime.InteropServices;

public class MouseWheelRedirector : IMessageFilter
{
    private static MouseWheelRedirector instance = null;
    private static bool _active = false;
    public static bool Active
    {
       get { return _active; }
       set
       { 
          if (_active != value) 
          {
             _active = value;
             if (_active)
             {
                if (instance == null)
                {
                    instance = new MouseWheelRedirector();
                }
                Application.AddMessageFilter(instance);
             }
             else
             {
                if (instance != null)
                {
                   Application.RemoveMessageFilter(instance);
                }
             }
          }
       }
    }

    public static void Attach(Control control)
    {
       if (!_active)
          Active = true;
       control.MouseEnter += instance.ControlMouseEnter;
       control.MouseLeave += instance.ControlMouseLeaveOrDisposed;
       control.Disposed += instance.ControlMouseLeaveOrDisposed;
    }

    public static void Detach(Control control)
    {
       if (instance == null)
          return;
       control.MouseEnter -= instance.ControlMouseEnter;
       control.MouseLeave -= instance.ControlMouseLeaveOrDisposed;
       control.Disposed -= instance.ControlMouseLeaveOrDisposed;
       if (object.ReferenceEquals(instance.currentControl, control))
          instance.currentControl = null;
    }

    private MouseWheelRedirector()
    {
    }


    private Control currentControl;
    private void ControlMouseEnter(object sender, System.EventArgs e)
    {
       var control = (Control)sender;
       if (!control.Focused)
       {
          currentControl = control;
       }
       else
       {
          currentControl = null;
       }
    }

    private void ControlMouseLeaveOrDisposed(object sender, System.EventArgs e)
    {
       if (object.ReferenceEquals(currentControl, sender))
       {
          currentControl = null;
       }
    }

    private const int WM_MOUSEWHEEL = 0x20a;
    public bool PreFilterMessage(ref System.Windows.Forms.Message m)
    {
       if (currentControl != null && m.Msg == WM_MOUSEWHEEL)
       {
          SendMessage(currentControl.Handle, m.Msg, m.WParam, m.LParam);
          return true;
       }
       else
       {
          return false;
       }
    }

    [DllImport("user32.dll", SetLastError = false)]
    private static extern IntPtr SendMessage(
       IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
 }


Answer 2:

我有类似的问题,发现这个线程...所以我发布迟来的答案为别人谁可能会发现这个线程。 就我而言,我只是想鼠标滚轮事件去到任何控制光标下...就像右键单击它(这将是令人困惑的,如果右击去聚焦控制,而不是光标下的控制......我认为这同样适用于鼠标滚轮正确的,除了我们已经习惯了它)。

无论如何,答案是超级容易。 只是PreFilterMessage添加到您的应用程序并重定向鼠标滚轮事件鼠标下的控制:

    public bool PreFilterMessage(ref Message m)
    {
        switch (m.Msg)
        {
            case WM_MOUSEWHEEL:   // 0x020A
            case WM_MOUSEHWHEEL:  // 0x020E
                IntPtr hControlUnderMouse = WindowFromPoint(new Point((int)m.LParam));
                if (hControlUnderMouse == m.HWnd)
                    return false; // already headed for the right control
                else
                {
                    // redirect the message to the control under the mouse
                    SendMessage(hControlUnderMouse, m.Msg, m.WParam, m.LParam);
                    return true;
                } 
             default: 
                return false; 
           } 
}


Answer 3:

使用Control.MouseEnter事件将焦点设置到该控件。 例如,使用ActiveControl属性



Answer 4:

这是布赖恩·肯尼迪的回答与汉克·舒尔茨评论完成:

首先,你应该做一个类实现IMessageFilter:

public class MessageFilter : IMessageFilter
{
    private const int WM_MOUSEWHEEL = 0x020A;
    private const int WM_MOUSEHWHEEL = 0x020E;

    [DllImport("user32.dll")]
    static extern IntPtr WindowFromPoint(Point p);
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    public bool PreFilterMessage(ref Message m)
    {
        switch (m.Msg)
        {
            case WM_MOUSEWHEEL:
            case WM_MOUSEHWHEEL:
                IntPtr hControlUnderMouse = WindowFromPoint(new Point((int)m.LParam));
                if (hControlUnderMouse == m.HWnd)
                {
                    //Do nothing because it's already headed for the right control
                    return false;
                }
                else
                {
                    //Send the scroll message to the control under the mouse
                    uint u = Convert.ToUInt32(m.Msg);   
                    SendMessage(hControlUnderMouse, u, m.WParam, m.LParam);
                    return true;
                }
            default:
                return false;
        }
    }
}

实例:

public partial class MyForm : Form
{
    MessageFilter mf = null;

    private void MyForm_Load(object sender, EventArgs e)
    {
        mf= new MessageFilter();
        Application.AddMessageFilter(mf);
    }

    private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        Application.RemoveMessageFilter(mf);
    }
}


文章来源: Mouse wheel event to work with hovered control