Pergunta

Eu tenho um problema com MouseEvents no meu aplicativo WinForm C #.

Eu quero ficar todas cliques do mouse sobre a minha candidatura, mas eu não quero colocar um ouvinte em cada componente filho nem usar gancho do Windows mouse.

Em Flash eu poderia colocar um ouvinte on Stage para obter todos os MouseEvents no filme.

Existe tal coisa em C #? A MouseListener global?


Editar:

Eu criar esta classe de IMessageFilter ans usado 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 colocar esse código nos controles que devem ouvir cliques globais:

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

Solução

Uma maneira simples de fazer isso é adicionar um filtro de mensagens de loop chamando Application.AddMessageFilter e escrever uma classe que implementa a interface IMessageFilter.

Via IMessageFilter.PreFilterMessage, sua classe consegue ver todas as mensagens entradas que passam pelo loop de mensagem do aplicativo. PreFilterMessage também começa a decidir se quer passar estas mensagens para o controle específico a que está destinada.

Um pedaço de complexidade que esta abordagem introduz é ter que lidar com mensagens do Windows, através do struct mensagem passada para o seu método PreFilterMessage. Isto significa que se referem ao documention Win32 em WM\_LBUTTONDOWN, WM\_MOUSEMOVE, WM\_LBUTTONUP etc, em vez dos eventos MouseDown, MouseMove e MouseUp convencionais.

Outras dicas

Amostra Class

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
}

Dê uma olhada neste artigo . Ele recursivamente hoooks todos os eventos de controle e os transmite. Você também pode substituir WndProc em seu formulário.

Se você não quer lidar com as mensagens, substituindo Form.PreProcessMessage ou Form.WndProc então você poderia subclasse Form para ligar um manipulador de eventos para todos os eventos MouseClick dos vários controles no formulário.
EDIT: Esqueci de recurse através de controles filho de controles no formulário

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

As suas formas, então, precisa derivar de MousePreviewForm não System.Windows.Forms.Form.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top