Pregunta Manejar un evento de clic en cualquier lugar dentro de un panel en C #


Tengo un panel en mi formulario con un controlador de eventos de clic. También tengo algunos otros controles dentro del panel (etiqueta, otros paneles, etc.). Quiero que el evento click se registre si hace clic en cualquier lugar dentro del panel. El evento de clic funciona siempre que no haga clic en ninguno de los controles dentro del panel, pero quiero disparar el evento sin importar dónde haga clic dentro del panel. ¿Es esto posible sin agregar el mismo evento de clic a todos los controles dentro del panel?


6
2017-10-13 18:12


origen


Respuestas:


Técnicamente es posible, aunque es muy feo. Necesitas captar el mensaje. antes de se envía al control que se hizo clic. Como puede hacer con IMessageFilter, puede detectar un mensaje de entrada que se eliminó de la cola de mensajes antes de enviarlo. Me gusta esto:

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;
    }
}

5
2017-10-13 19:08



Necesitaba exactamente la misma funcionalidad hoy, así que esto se prueba y funciona:

1: Crea un subclase que te pueda arrebatar tu ratón:

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: Inicialice el snatcher para enganchar en el panel WndProc:

    private MessageSnatcher _snatcher;

    public Form1()
    {
        InitializeComponent();

        _snatcher = new MessageSnatcher(this.panel1);
    }

3: El snatcher de mensajes obtendrá el WM_PARENTNOTIFY si hace clic en un control secundario.


1
2017-10-13 18:32



Solía ​​ser capaz de anular el método OnBubbleEvent en el control. En WPF, el mecanismo se llama eventos enrutados: http://weblogs.asp.net/vblasberg/archive/2010/03/30/wpf-routed-events-bubbling-several-layers-up.aspx


0
2017-10-13 18:30



Poco tarde en la fiesta, pero lo que hice fue mapear todo el evento de clic de todos los controles dentro del panel al evento de clic de panel. Sé que su enfoque desagradable. ¡¡pero hey!!


0
2018-02-26 13:59