Pregunta

Tengo un problema con MouseEvents en mi aplicación WinForm C #.

Quiero obtener todos clics del mouse en mi aplicación, pero no quiero incluir a un oyente en todos los componentes secundarios ni utilizar el gancho del mouse de Windows.

En Flash podría poner a un oyente en el escenario para obtener todos los eventos del ratón en la película.

¿Hay tal cosa en C #? ¿Un MouseListener global?


Editar:

Creo esta clase de IMessageFilter y uso Application.AddMessageFilter.

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 coloque este código en los controles que necesitan escuchar clics globales:

GlobalMouseHandler globalClick = new GlobalMouseHandler();
Application.AddMessageFilter(globalClick);
¿Fue útil?

Solución

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

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

Una parte de la complejidad que presenta este enfoque es tener que lidiar con los mensajes de Windows, a través de la estructura de mensajes que se pasa a su método PreFilterMessage . Esto significa referirse a la documentación de Win32 en WM \ _LBUTTONDOWN, WM \ _MOUSEMOVE , WM \ _LBUTTONUP etc., en lugar del MouseDown convencional, MouseMove y MouseUp .

Otros consejos

Clase de muestra

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
}

Echa un vistazo a este artículo . Recoge de forma recursiva todos los eventos de control y los difunde. También puede anular WndProc en su formulario.

Si no desea manejar los mensajes anulando Form.PreProcessMessage o Form.WndProc, puede hacer una subclase de Form para enlazar un controlador de eventos a todos los eventos de MouseClick desde los diversos controles del formulario.
EDITAR: se olvidó de responder 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 formularios tendrían que derivarse de MousePreviewForm, no de System.Windows.Forms.Form.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top