Winforms 订阅表单中所有控件的鼠标事件

Winforms 订阅表单中所有控件的鼠标事件,winforms,events,mouse,Winforms,Events,Mouse,我怎样才能轻松捕获表单中所有控件的“鼠标按下”事件,而不必手动订阅每个事件?(C#) 类似于“KeyPreview”功能,但用于鼠标事件。表单中的其他控件无法侦听表单的鼠标事件处理程序。因为每个控件都有自己的鼠标事件列表器 但您可以将每个控件的鼠标事件订阅到窗体鼠标事件 this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MDown); this.label1.MouseDown += new S

我怎样才能轻松捕获表单中所有控件的“鼠标按下”事件,而不必手动订阅每个事件?(C#)
类似于“KeyPreview”功能,但用于鼠标事件。

表单中的其他控件无法侦听表单的鼠标事件处理程序。因为每个控件都有自己的鼠标事件列表器

但您可以将每个控件的鼠标事件订阅到窗体鼠标事件

this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MDown);    
this.label1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MDown); 
this.ListBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MDown);

这样,您可以为所有控件鼠标事件使用单个处理程序。

解决方案1

订阅表单中每个控件上的每个事件肯定是最简单的方法,因为您只需要使用Ramesh给出的代码

但是,另一种技术涉及覆盖父控件上的默认windows消息处理方法(“WndProc”)——在本例中,是包含所有控件的窗体。 这有一个副作用,当鼠标光标移动到另一个父控件中包含的控件上时,您将无法检测到该副作用

例如,您将无法检测鼠标光标何时位于
选项卡控件中包含的
文本框
上。这是因为
TabControl
将继续处理所有鼠标事件

解决方案2

下面的解决方案将克服在尝试使用称为windows挂钩的技术检测鼠标光标位于哪个控件上时出现的所有问题

钩子本质上允许我们捕获鼠标和键盘事件,甚至在它们被发送到具有焦点的窗口之前

以下是一个示例:

  public enum HookType : int
  {
   WH_JOURNALRECORD = 0,
   WH_JOURNALPLAYBACK = 1,
   WH_KEYBOARD = 2,
   WH_GETMESSAGE = 3,
   WH_CALLWNDPROC = 4,
   WH_CBT = 5,
   WH_SYSMSGFILTER = 6,
   WH_MOUSE = 7,
   WH_HARDWARE = 8,
   WH_DEBUG = 9,
   WH_SHELL = 10,
   WH_FOREGROUNDIDLE = 11,
   WH_CALLWNDPROCRET = 12,
   WH_KEYBOARD_LL = 13,
   WH_MOUSE_LL = 14
  }

  [StructLayout(LayoutKind.Sequential)]
  public struct POINT
  {
   public int X;
   public int Y;
  }

  [StructLayout(LayoutKind.Sequential)]
  public struct MouseHookStruct
  {
   public POINT pt;
   public int hwnd;
   public int hitTestCode;
   public int dwExtraInfo;
  }

  [DllImport("user32.dll", SetLastError = true)]
  static extern int SetWindowsHookEx(HookType hook, HookProc callback, IntPtr hInstance, uint dwThreadId);

  [DllImport("user32.dll", SetLastError= true)]
  static extern int CallNextHookEx(int hook,  int code, IntPtr wParam, IntPtr lParam);

  [DllImport("kernel32.dll")]
  static extern int GetLastError();

  [DllImport("kernel32.dll")]
  static extern int GetCurrentThreadId();

  public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
  private static int hHook;

  public Form1()
  {
   InitializeComponent();

   hHook = SetWindowsHookEx(HookType.WH_MOUSE, MouseHookProc, IntPtr.Zero, (uint)GetCurrentThreadId());
   if (hHook == 0)
    MessageBox.Show("GetLastError: " + GetLastError());
  }

  private int MouseHookProc(int code, IntPtr wParam, IntPtr lParam)
  {
   //Marshall the data from the callback.
   MouseHookStruct mouseInfo = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));

   if (code < 0)
   {
    return CallNextHookEx(hHook, code, wParam, lParam);
   }
   else
   {
    //Create a string variable that shows the current mouse coordinates.
    String strCaption = "x = " + mouseInfo.pt.X.ToString("d") +
     "  y = " + mouseInfo.pt.Y.ToString("d");

    //You must get the active form because it is a static function.
    Form tempForm = Form.ActiveForm;

    Control c = Control.FromHandle((IntPtr)mouseInfo.hwnd);
    if (c != null)
     label1.Text = c.Name;
    else
     label1.Text = "Control not found";

    //Set the caption of the form.
    tempForm.Text = strCaption;

    return CallNextHookEx(hHook, code, wParam, lParam);
   }
  }
公共枚举类型:int
{
WH_JOURNALRECORD=0,
WH_JOURNALPLAYBACK=1,
WH_键盘=2,
WH_GETMESSAGE=3,
WH_CALLWNDPROC=4,
WH_CBT=5,
WH_SYSMSGFILTER=6,
WH_鼠标=7,
WH_硬件=8,
WH_DEBUG=9,
WH_外壳=10,
WH_FOREGROUNDIDLE=11,
WH_CALLWNDPROCRET=12,
WH_KEYBOARD_LL=13,
WH_鼠标\u LL=14
}
[StructLayout(LayoutKind.Sequential)]
公共结构点
{
公共int X;
公共智力;
}
[StructLayout(LayoutKind.Sequential)]
公共结构MouseHookStruct
{
公共点;
公共卫生署;
公共int-hitTestCode;
公共信息;
}
[DllImport(“user32.dll”,SetLastError=true)]
静态外部int SetWindowsHookEx(HookType钩子、HookProc回调、IntPtr hInstance、uint dwThreadId);
[DllImport(“user32.dll”,SetLastError=true)]
静态extern int CallNextHookEx(int hook、int代码、IntPtr wParam、IntPtr lParam);
[DllImport(“kernel32.dll”)]
静态外部int GetLastError();
[DllImport(“kernel32.dll”)]
静态外部int GetCurrentThreadId();
公共委托int-HookProc(int-nCode、IntPtr-wParam、IntPtr-lParam);
私有静态int-hHook;
公共表格1()
{
初始化组件();
hHook=SetWindowsHookEx(HookType.WH_MOUSE,MouseHookProc,IntPtr.Zero,(uint)GetCurrentThreadId());
如果(hHook==0)
Show(“GetLastError:+GetLastError());
}
私有int-MouseHookProc(int-code、IntPtr-wParam、IntPtr-lParam)
{
//整理回调中的数据。
MouseHookStruct mouseInfo=(MouseHookStruct)Marshal.PtrToStructure(lParam,typeof(MouseHookStruct));
如果(代码<0)
{
返回CallNextHookEx(hHook、code、wParam、lParam);
}
其他的
{
//创建一个显示当前鼠标坐标的字符串变量。
字符串strcation=“x=“+mouseInfo.pt.x.ToString(“d”)+
“y=“+mouseInfo.pt.y.ToString(“d”);
//您必须获取活动窗体,因为它是一个静态函数。
Form tempForm=Form.ActiveForm;
Control c=Control.FromHandle((IntPtr)mouseInfo.hwnd);
如果(c!=null)
标签1.Text=c.名称;
其他的
label1.Text=“未找到控件”;
//设置窗体的标题。
tempForm.Text=stroption;
返回CallNextHookEx(hHook、code、wParam、lParam);
}
}

我发现这是最适合我的解决方案

创建从
IMessageFilter
派生的新类:

public class GlobalMouseHandler : IMessageFilter
{

    private const int WM_LBUTTONDOWN = 0x201;

    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg == WM_LBUTTONDOWN)
        {
            // do something
            ((YourMainForm)Form.ActiveForm).YourMainForm_Click(null, null);
        }
        return false;
    }
}
然后在主窗体中添加以下内容以注册消息筛选器:

GlobalMouseHandler globalClick = new GlobalMouseHandler();
Application.AddMessageFilter(globalClick);
并以您的形式添加此函数以执行您必须执行的操作:

public void YourMainForm_Click(object sender, EventArgs e)
{
    // do anything here...
}