2009-04-29 9 views
28

Ich habe ein Problem mit MouseEvents auf meiner WinForm C# -Anwendung. Ich möchte alle Mausklicks auf meine Anwendung bekommen, aber ich möchte nicht in jeder untergeordneten Komponente einen Listener setzen, weder Windows-Maus-Hook verwenden.Erfassen von Mausereignissen aus jeder Komponente in C# WinForm

Auf Flash konnte ich einen Listener auf Stage setzen, um alle MouseEvents auf dem Film zu erhalten. Gibt es so etwas auf C#? Ein globaler MouseListener?


Edit: Ich schaffe diese Klasse von IMessageFilter ans verwendet 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; 
    } 
} 

Und diesen Code auf die Kontrollen stellen die globale Klicks hören müssen:

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

Vielen Dank für die Hilfe!

Antwort

14

Ein einfacher Weg, dies zu tun, ist ein Meldungsschleifenfilter durch Aufruf Application.AddMessageFilter und Schreiben einer Klasse, die die IMessageFilter Schnittstelle implementiert.

Über IMessageFilter.PreFilterMessage erhält Ihre Klasse alle Eingaben Nachrichten, die die Nachrichtenschleife Ihrer Anwendung durchlaufen. PreFilterMessage kann auch entscheiden, ob diese Nachrichten an das bestimmte Steuerelement weitergeleitet werden, für das sie bestimmt sind.

Ein Teil der Komplexität, die dieser Ansatz einführt, ist, mit Windows-Nachrichten umzugehen, über die Nachrichtenstruktur, die an Ihre PreFilterMessage-Methode übergeben wird. Dies bezieht sich auf die Win32-Dokumentation unter WM\_LBUTTONDOWN, WM\_MOUSEMOVE, WM\_LBUTTONUP usw. anstelle der herkömmlichen Ereignisse MouseDown, MouseMove und MouseUp.

+0

Vielen Dank für die Hilfe! Alles funktioniert gut. Ich habe Application.AddMessageFilter mit suscess. Ich haken die Mausereignisse und erstellen einen C# MouseEventHandler, um das Ereignis auf WinForm-Ebene an andere Steuerelemente zu senden. –

2

Take a look at this article. Es rekursiv hookt alle Kontrollereignisse und sendet sie. Sie könnten auch WndProc in Ihrem Formular überschreiben.

+2

Ich habe versucht, WinProc zu überschreiben, aber endete mit dem gleichen Problem: Mausklicks wurden nur gefangen, wenn ich direkt über das Formular geklickt habe. Wenn ich auf ein Kind klickte, wurde Control Winproc nicht aufgerufen. –

3

Wenn Sie die Nachrichten nicht durch Überschreiben von Form.PreProcessMessage oder Form.WndProc behandeln möchten, können Sie die Unterklasse Form verwenden, um einen Ereignishandler für alle MouseClick-Ereignisse aus den verschiedenen Steuerelementen im Formular einzubinden.
EDIT: vergessen, durch untergeordnete Steuerelemente der Steuerelemente auf dem Formular recurse.

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

Ihre Formulare würden dann von MousePreviewForm nicht System.Windows.Forms.Form ableiten müssen.

+0

Sie könnten sogar das Form.OnControlAdded-Ereignis verwenden, um den AllControlsMouseClick -Handler anzuwenden. –

+0

Aber ich kann nicht nur die ersten Childs des Formulars durchlaufen, ich muss tief in jedes Control gehen und das AllControlsMouseClick auch seinen Childs hinzufügen. –

+0

Die Rekursion von Childs-Komponenten ist ein guter Tatic. Aber ich möchte keinem Steuerelement einen Listener hinzufügen. Für Mausereignisse funktioniert der Application.AddMessageFilter, aber ich denke, Ihre Idee ist gut für andere Arten von Ereignissen. Danke für die Hilfe! –

4

Probe Klasse

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 
} 
Verwandte Themen