2010-10-13 15 views
6

Tengo un panel en mi Formulario con un controlador de evento 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 activar 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?Manejo de un evento de clic en cualquier lugar dentro de un panel en C#

+0

¿Es este WPF .....? –

+1

No, solo una aplicación de formularios de windows normal –

Respuesta

1

que necesitaba la misma funcionalidad exacta de hoy, por lo que este se ha probado y funciona:

1: Crear un subclasser que puede arrebatar el clic de 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: Inicializar el ladrón para conectar en el panel de WndProc:

private MessageSnatcher _snatcher; 

    public Form1() 
    { 
     InitializeComponent(); 

     _snatcher = new MessageSnatcher(this.panel1); 
    } 

3: el ladrón de mensaje tendrá la WM_PARENTNOTIFY si hace clic en un chi ld control.

5

Técnicamente es posible, aunque es muy feo. Debe capturar el mensaje antes de que se envía al control que se hizo clic. Lo que puede hacer con IMessageFilter, puede oler un mensaje de entrada que se eliminó de la cola de mensajes antes de enviarlo. De esta manera:

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

+1 También hice esto y acepto que debería funcionar bien. Mi única advertencia es que básicamente se une a la bomba de mensajes de eventos de aplicaciones, así que asegúrese de hacer lo que haga en el paso "Hacer algo con esto ...", hacerlo rápido y eficiente. –

+1

Meh, ya está filtrado para el panel y el mensaje. Este código se ejecuta en tiempo humano. –

0

poco tarde a la fiesta, pero lo que hice fue mapear todo el evento click de todos los controles en el interior del panel de eventos del panel de clic. Sé que su enfoque desagradable. ¡¡pero hey!!

Cuestiones relacionadas