2012-06-14 14 views
9

Nella mia applicazione Windows Form C# 3.5, ho alcuni SplitContainer. C'è un controllo di lista all'interno di ciascuna (riempimento del bacino). Quando l'attenzione è su uno di questi controlli e muovo la rotella del mouse, l'elenco, che è ora focalizzato, viene fatto scorrere.Evento della rotellina del mouse per funzionare con il controllo a distanza

Il mio compito è far scorrere la lista, che al momento è al passaggio del mouse, non quella che è selezionata. È possibile in Windows Form? In caso contrario, è possibile con PInvoke?

+0

Sembra che abbiano fatto "scorrere il puntatore del mouse sopra" il comportamento standard in Windows 10. Che è piuttosto fastidioso nella maggior parte dei casi, in realtà. – Nyerguds

risposta

9

Sembra che sia possibile utilizzare lo IMessageFilter e PInvoke per gestirlo. Un esempio in VB può essere trovato a Redirect Mouse Wheel Events to Unfocused Windows Forms Controls. Dovresti essere in grado di convertire facilmente questo in C#.

Punti di Interesse

Questa classe utilizza le seguenti tecniche per il compito affidato:

  • ascoltare eventi MouseEnter e MouseLeave del controllo per determinare quando il puntatore del mouse viene spostato sul controllo.
  • Implementare IMessageFilter per catturare i messaggi WM_MOUSEWHEEL nell'applicazione.
  • PInvviare la chiamata API di Windows SendMessage reindirizzare il messaggio WM_MOUSEWHEEL all'handle del controllo.
  • L'oggetto IMessageFilter viene implementato come un singleton della classe MouseWheelRedirector e accessibile dai membri condivisi Attach, Detach e Active.

Utilizzando a VB.NET to C# converter, questo è ciò che si finisce con:

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Data; 
using System.Diagnostics; 

using System.Windows.Forms; 
using System.Runtime.InteropServices; 

public class MouseWheelRedirector : IMessageFilter 
{ 
    private static MouseWheelRedirector instance = null; 
    private static bool _active = false; 
    public static bool Active 
    { 
     get { return _active; } 
     set 
     { 
      if (_active != value) 
      { 
      _active = value; 
      if (_active) 
      { 
       if (instance == null) 
       { 
        instance = new MouseWheelRedirector(); 
       } 
       Application.AddMessageFilter(instance); 
      } 
      else 
      { 
       if (instance != null) 
       { 
        Application.RemoveMessageFilter(instance); 
       } 
      } 
      } 
     } 
    } 

    public static void Attach(Control control) 
    { 
     if (!_active) 
      Active = true; 
     control.MouseEnter += instance.ControlMouseEnter; 
     control.MouseLeave += instance.ControlMouseLeaveOrDisposed; 
     control.Disposed += instance.ControlMouseLeaveOrDisposed; 
    } 

    public static void Detach(Control control) 
    { 
     if (instance == null) 
      return; 
     control.MouseEnter -= instance.ControlMouseEnter; 
     control.MouseLeave -= instance.ControlMouseLeaveOrDisposed; 
     control.Disposed -= instance.ControlMouseLeaveOrDisposed; 
     if (object.ReferenceEquals(instance.currentControl, control)) 
      instance.currentControl = null; 
    } 

    private MouseWheelRedirector() 
    { 
    } 


    private Control currentControl; 
    private void ControlMouseEnter(object sender, System.EventArgs e) 
    { 
     var control = (Control)sender; 
     if (!control.Focused) 
     { 
      currentControl = control; 
     } 
     else 
     { 
      currentControl = null; 
     } 
    } 

    private void ControlMouseLeaveOrDisposed(object sender, System.EventArgs e) 
    { 
     if (object.ReferenceEquals(currentControl, sender)) 
     { 
      currentControl = null; 
     } 
    } 

    private const int WM_MOUSEWHEEL = 0x20a; 
    public bool PreFilterMessage(ref System.Windows.Forms.Message m) 
    { 
     if (currentControl != null && m.Msg == WM_MOUSEWHEEL) 
     { 
      SendMessage(currentControl.Handle, m.Msg, m.WParam, m.LParam); 
      return true; 
     } 
     else 
     { 
      return false; 
     } 
    } 

    [DllImport("user32.dll", SetLastError = false)] 
    private static extern IntPtr SendMessage(
     IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); 
} 
+0

Questo non sembra funzionare con i touch pad più comuni utilizzando metodi come lo scorrimento con il lato destro o con il doppio dito. Sembra che i loro driver facciano qualche magia nera per inviare i messaggi di scorrimento direttamente alle barre di scorrimento del controllo invece di inviare 'WM_MOUSEWHEEL' al controllo come dovrebbero. Qualche idea su come aggirare questo? – Nyerguds

+0

Hmm. Sembra che NumericUpDown non voglia ascoltarlo. – Nyerguds

5

avevo domanda simile e ho trovato questa discussione ... così distacco la mia risposta tardiva per gli altri che potrebbero trovare questo thread. Nel mio caso, voglio solo che gli eventi della rotellina del mouse vadano a qualsiasi controllo sia sotto il cursore ... proprio come fa il clic destro (sarebbe sconcertante se il tasto destro del mouse andasse al controllo della messa a fuoco piuttosto che al controllo sotto il cursore ... Io sostengo che lo stesso vale per la rotella del mouse, tranne che ci siamo abituati).

In ogni caso, la risposta è semplicissima. Basta aggiungere un PreFilterMessage alla vostra applicazione e farlo reindirizzare gli eventi della rotella del mouse per il controllo sotto il mouse:

public bool PreFilterMessage(ref Message m) 
    { 
     switch (m.Msg) 
     { 
      case WM_MOUSEWHEEL: // 0x020A 
      case WM_MOUSEHWHEEL: // 0x020E 
       IntPtr hControlUnderMouse = WindowFromPoint(new Point((int)m.LParam)); 
       if (hControlUnderMouse == m.HWnd) 
        return false; // already headed for the right control 
       else 
       { 
        // redirect the message to the control under the mouse 
        SendMessage(hControlUnderMouse, m.Msg, m.WParam, m.LParam); 
        return true; 
       } 
      default: 
       return false; 
      } 
} 
+0

Ne manca un po '. È necessario DllImport WindowFromPoint() e SendMessage: '[DllImport (" user32.dll ")] extern statico IntPtr WindowFromPoint (Punto p); [DllImport (" user32.dll ", CharSet = CharSet.Auto)] static extern IntPtr SendMessage (hWnd IntPtr, UInt32 Msg, IntPtr wParam, lParam IntPtr); ' Inoltre, PreFilterMessage() proviene da IMessageFilter, e che l'attuazione deve essere passato a' ApplicationAddMessageFilter() '. Una volta fatto, tutti i pannelli della mia app si sono fatti scorrere sotto il mouse. Tuttavia, facendo doppio clic non viene più evidenziato il testo. Dispari. –

2

Questo è Brian risposta Kennedy s' completata con Hank Schultz commento:

First si dovrebbe fare una classe implementa IMessageFilter:

public class MessageFilter : IMessageFilter 
{ 
    private const int WM_MOUSEWHEEL = 0x020A; 
    private const int WM_MOUSEHWHEEL = 0x020E; 

    [DllImport("user32.dll")] 
    static extern IntPtr WindowFromPoint(Point p); 
    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); 

    public bool PreFilterMessage(ref Message m) 
    { 
     switch (m.Msg) 
     { 
      case WM_MOUSEWHEEL: 
      case WM_MOUSEHWHEEL: 
       IntPtr hControlUnderMouse = WindowFromPoint(new Point((int)m.LParam)); 
       if (hControlUnderMouse == m.HWnd) 
       { 
        //Do nothing because it's already headed for the right control 
        return false; 
       } 
       else 
       { 
        //Send the scroll message to the control under the mouse 
        uint u = Convert.ToUInt32(m.Msg); 
        SendMessage(hControlUnderMouse, u, m.WParam, m.LParam); 
        return true; 
       } 
      default: 
       return false; 
     } 
    } 
} 

Esempio utilizzo:

public partial class MyForm : Form 
{ 
    MessageFilter mf = null; 

    private void MyForm_Load(object sender, EventArgs e) 
    { 
     mf= new MessageFilter(); 
     Application.AddMessageFilter(mf); 
    } 

    private void MyForm_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     Application.RemoveMessageFilter(mf); 
    } 
} 
Problemi correlati