Domanda

Ho un problema con MouseEvents sulla mia applicazione WinForm C #.

Voglio ottenere tutti clic del mouse sulla mia applicazione, ma non voglio mettere un ascoltatore in ogni componente figlio né usare l'hook del mouse di Windows.

Su Flash ho potuto mettere un ascoltatore sul palco per ottenere tutti gli MouseEvent nel film.

C'è qualcosa del genere su C #? Un MouseListener globale?


Modifica

Creo questa classe da IMessageFilter e ho usato 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;
    }
}

E metti questo codice sui controlli che devono ascoltare i clic globali:

GlobalMouseHandler globalClick = new GlobalMouseHandler();
Application.AddMessageFilter(globalClick);
È stato utile?

Soluzione

Un modo semplice per farlo è quello di aggiungere un filtro per loop di messaggi chiamando Application.AddMessageFilter e scrivendo una classe che implementa l'interfaccia IMessageFilter .

Tramite IMessageFilter.PreFilterMessage , la tua classe vede tutti i messaggi di input che passano attraverso il ciclo di messaggi dell'applicazione. PreFilterMessage può anche decidere se passare questi messaggi al controllo specifico a cui sono destinati.

Una parte della complessità introdotta da questo approccio è la gestione dei messaggi di Windows, tramite la struttura del messaggio passata al metodo PreFilterMessage . Questo significa riferirsi alla documentazione Win32 su WM \ _LBUTTONDOWN, WM \ _MOUSEMOVE , WM \ _LBUTTONUP ecc., Invece del convenzionale MouseDown , MouseMove e MouseUp .

Altri suggerimenti

Classe di esempio

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
}

Dai un'occhiata a questo articolo . Cerca ricorsivamente tutti gli eventi di controllo e li trasmette. Puoi anche sostituire WndProc nella tua forma.

Se non si desidera gestire i messaggi sovrascrivendo Form.PreProcessMessage o Form.WndProc, è possibile sottoclassare Form per agganciare un gestore eventi a tutti gli eventi MouseClick dai vari controlli del modulo.
EDIT: dimenticato di ricorrere a controlli figlio sui controlli nel modulo.

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

I tuoi moduli dovrebbero quindi derivare da MousePreviewForm e non da System.Windows.Forms.Form.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top