2009-04-29 46 views
28

Tengo un problema con MouseEvents en mi aplicación WinForm C#. Quiero obtener TODOS los clics del mouse en mi aplicación, pero no quiero poner un oyente en cada componente secundario ni usar el gancho del mouse de Windows.Capturar eventos de mouse de cada componente en C# WInForm

En Flash pude poner un oyente en el escenario para obtener todos los eventos de ratón en la película. ¿Existe tal cosa en C#? ¿Un mouseListener global?


Editar: que crear esta clase de IMessageFilter ans Application.AddMessageFilter utilizado.

public class GlobalMouseHandler : IMessageFilter{ 

    private const int WM_LBUTTONDOWN = 0x201; 

    public bool PreFilterMessage(ref Message m){ 
     if (m.Msg == WM_LBUTTONDOWN) { 
      // Do stuffs 
     } 
     return false; 
    } 
} 

Y poner este código en los controles que necesitan escuchar clics globales:

GlobalMouseHandler globalClick = new GlobalMouseHandler(); 
Application.AddMessageFilter(globalClick); 

Gracias por la ayuda!

Respuesta

14

Una forma directa de hacerlo es agregar un filtro de bucle de mensaje llamando al Application.AddMessageFilter y escribiendo una clase que implemente la interfaz IMessageFilter.

A través de IMessageFilter.PreFilterMessage, su clase puede ver los mensajes de entradas que pasan por el bucle de mensajes de su aplicación. PreFilterMessage también decide si pasar estos mensajes al control específico al que están destinados.

Una parte de la complejidad que presenta este enfoque es tener que ocuparse de los mensajes de Windows, a través de la estructura del mensaje pasada al método PreFilterMessage. Esto significa hacer referencia a la documentación de Win32 en WM\_LBUTTONDOWN, WM\_MOUSEMOVE, WM\_LBUTTONUP etc., en lugar de los eventos MouseDown, MouseMove y MouseUp convencionales.

+0

Gracias por la ayuda! Todo funciona bien Utilicé Application.AddMessageFilter con suscess. Engancho los eventos del mouse y creo un C# MouseEventHandler para enviar el evento en el nivel de WinForm a otros controles. –

2

Take a look at this article. Acurruca de manera recursiva todos los eventos de control y los transmite. También puede anular WndProc en su formulario.

+2

Traté de anular WinProc, pero finalicé con el mismo problema: los clics del mouse solo se captaban cuando hacía clic directamente sobre el formulario. Si hice clic en un control de niño Winproc no fue llamado. –

3

Si no desea controlar los mensajes anulando Form.PreProcessMessage o Form.WndProc, puede crear una subclase de Formulario para conectar un controlador de eventos a todos los eventos MouseClick de los diversos controles del formulario.
EDITAR: olvidó recurse a través de controles secundarios de controles en el formulario.

public class MousePreviewForm : Form 
    { 
     protected override void OnClosed(EventArgs e) 
     { 
     UnhookControl(this as Control); 
     base.OnClosed(e); 
     } 

     protected override void OnLoad(EventArgs e) 
     { 
     base.OnLoad(e); 

     HookControl(this as Control); 
     } 

     private void HookControl(Control controlToHook) 
     { 
     controlToHook.MouseClick += AllControlsMouseClick; 
     foreach (Control ctl in controlToHook.Controls) 
     { 
      HookControl(ctl); 
     }  
     } 

     private void UnhookControl(Control controlToUnhook) 
     { 
     controlToUnhook.MouseClick -= AllControlsMouseClick; 
     foreach (Control ctl in controlToUnhook.Controls) 
     { 
      UnhookControl(ctl); 
     } 
     } 

     void AllControlsMouseClick(object sender, MouseEventArgs e) 
     { 
     //do clever stuff here... 
     throw new NotImplementedException(); 
     } 
    } 

Sus formas serían continuación, tendrá que derivar de MousePreviewForm no System.Windows.Forms.Form.

+0

Incluso podría usar el evento Form.OnControlAdded para aplicar el controlador AllControlsMouseClick. –

+0

Pero no solo puedo recorrer el primer Childs de la forma, necesito profundizar en cada Control y agregar AllControlsMouseClick a sus Childs también. –

+0

La recursión de componentes de los niños es un buen tático. Pero no quiero agregar un oyente a cada control. Para eventos de mouse, Application.AddMessageFilter funciona, pero creo que su idea es buena para otros tipos de eventos. ¡Gracias por la ayuda! –

4

de clase de ejemplo

class CaptureEvents : IMessageFilter 
{ 
    #region IMessageFilter Members 
    public delegate void Callback(int message); 
    public event Callback MessageReceived; 

    IntPtr ownerWindow; 
    Hashtable interestedMessages = null; 
    CaptureEvents(IntPtr handle, int[] messages) 
    { 
     ownerWindow = handle; 
     for(int c = 0; c < messages.Length ; c++) 
     { 
      interestedMessages[messages[c]] = 0; 
     } 
    } 
    public bool PreFilterMessage(ref Message m) 
    { 
     if (m.HWnd == ownerWindow && interestedMessages.ContainsKey(m.Msg)) 
     { 
      MessageReceived(m.Msg); 
     } 
     return true; 
    } 

    #endregion 
} 
Cuestiones relacionadas