簡體   English   中英

鼠標滾輪事件與懸停控件一起使用

[英]Mouse wheel event to work with hovered control

在我的C#3.5 Windows窗體應用程序中,我有一些SplitContainers。 每個內部都有一個列表控件(dock fill)。 當焦點位於其中一個控件上並移動鼠標滾輪時,滾動顯示現在聚焦的列表。

我的任務是滾動列表,該列表當前是鼠標懸停的,而不是選中的列表。 是否可以在Windows窗體中? 如果沒有,是否可以使用PInvoke?

看起來你可以使用IMessageFilter和PInvoke來處理這個問題。 可以在將鼠標滾輪事件重定向到未聚焦的Windows窗體控件中找到VB中的示例。 您應該能夠輕松地將其轉換為C#。

興趣點

此類對給定任務使用以下技術:

  • 監聽控件的MouseEnter和MouseLeave事件,以確定鼠標指針何時在控件上。
  • 實現IMessageFilter以捕獲應用程序中的WM_MOUSEWHEEL消息。
  • PInvoke Windows API調用SendMessage將WM_MOUSEWHEEL消息重定向到控件的句柄。
  • IMessageFilter對象實現為MouseWheelRedirector類的單例,並由共享成員Attach,Detach和Active訪問。

使用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);
 }

我有類似的問題,並找到了這個帖子......所以發布我的遲來的答案給其他可能找到這個帖子的人。 在我的情況下,我只是希望鼠標滾輪事件轉到光標下的任何控件...就像右鍵單擊一樣(如果右鍵單擊轉到焦點控件而不是光標下的控件,那將會很困惑...我認為鼠標輪也是如此,除了我們已經習慣了它。

無論如何,答案非常簡單。 只需將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; 
           } 
}

使用Control.MouseEnter Event將焦點設置為控件。 例如,使用ActiveControl屬性

這是布朗肯尼迪的回答與漢克舒爾茨的評論:

首先,你應該讓一個類實現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);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM