在C#中的面板内的任何位置处理click事件

时间:2010-10-13 18:12:22

标签: c# winforms

我的表单中有一个面板,带有一个单击事件处理程序。我还在面板内部有一些其他控件(标签,其他面板等)。如果您单击面板内的任何位置,我希望单击事件进行注册。只要我没有单击面板内的任何控件,click事件就会起作用,但无论你在面板内单击什么位置,我都想触发事件。如果没有向面板内的所有控件添加相同的单击事件,这是否可行?

5 个答案:

答案 0 :(得分:5)

技术上有可能,虽然非常丑陋。您需要在之前捕获消息,然后将其发送到单击的控件。您可以使用IMessageFilter执行此操作,您可以在调度之前嗅探从消息队列中删除的输入消息。像这样:

using System;
using System.Drawing;
using System.Windows.Forms;

class MyPanel : Panel, IMessageFilter {
    public MyPanel() {
        Application.AddMessageFilter(this);
    }
    protected override void Dispose(bool disposing) {
        if (disposing) Application.RemoveMessageFilter(this);
        base.Dispose(disposing);
    }
    public bool PreFilterMessage(ref Message m) {
        if (m.HWnd == this.Handle) {
            if (m.Msg == 0x201) {  // Trap WM_LBUTTONDOWN
                Point pos = new Point(m.LParam.ToInt32());
                // Do something with this, return true if the control shouldn't see it
                //...
                // return true
            }
        }
        return false;
    }
}

答案 1 :(得分:1)

我今天需要完全相同的功能,因此经过测试并且有效:

1:创建一个子抓取器,可以抓住你的鼠标点击:

internal class MessageSnatcher : NativeWindow
{
    public event EventHandler LeftMouseClickOccured = delegate{};

    private const int WM_LBUTTONDOWN = 0x201;
    private const int WM_PARENTNOTIFY = 0x210;

    private readonly Control _control;

    public MessageSnatcher(Control control)
    {
        if (control.Handle != IntPtr.Zero)
            AssignHandle(control.Handle);
        else
            control.HandleCreated += OnHandleCreated;

        control.HandleDestroyed += OnHandleDestroyed;
        _control = control;
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_PARENTNOTIFY)
        {
            if (m.WParam.ToInt64() == WM_LBUTTONDOWN)
                LeftMouseClickOccured(this, EventArgs.Empty);
        }

        base.WndProc(ref m);
    }

    private void OnHandleCreated(object sender, EventArgs e)
    {
        AssignHandle(_control.Handle);
    }

    private void OnHandleDestroyed(object sender, EventArgs e)
    {
        ReleaseHandle();
    }
}

2:初始化抓取器以挂钩面板WndProc:

    private MessageSnatcher _snatcher;

    public Form1()
    {
        InitializeComponent();

        _snatcher = new MessageSnatcher(this.panel1);
    }

3:如果单击子控件,Message snatcher将获取WM_PARENTNOTIFY。

答案 2 :(得分:0)

您曾经能够覆盖控件上的OnBubbleEvent方法。在WPF中,该机制称为路由事件:http://weblogs.asp.net/vblasberg/archive/2010/03/30/wpf-routed-events-bubbling-several-layers-up.aspx

答案 3 :(得分:0)

派对迟到了,但我所做的是将面板内所有控件的所有点击事件映射到面板点击事件。我知道它讨厌的做法。但是嘿!!

答案 4 :(得分:0)

一个简单的解决方案: 用户控件中的每个控件都获得相同的点击事件“ControlClick”。用户控件事件单击适用于内部的任何控件。

private void ControlClick(Object sender, EventArgs e)
 {
    if (sender is UC_Vorgang uC_vorgang)
    {
        uC_vorgang.OnClick(e);
    }
    else
    {
        ControlClick(((Control)sender).Parent, e);
    }
}