2016-04-15 17 views
1

WM_MOUSEWHEEL Nachrichten werden mit dem Fokus an die Steuerung gesendet. Meine Anwendung hat eine komplexe Steuerungshierarchie mit Steuerelementen, die andere Steuerelemente enthalten, von denen einige unsichtbar oder überlappend sind. Ich möchte mit dem Mausrad eine bestimmte ScrollableControl scrollen.Wie leite ich Mausradmeldungen von einem Fenster zum anderen um?

This question hat eine Antwort mit einer IMessageFilter Implementierung, die Nachrichten WM_MOUSEWHEEL fängt. Das funktioniert gut und ich sehe die Nachrichten gefangen werden. Ich versuchte ScrollableControls VerticalScroll Eigenschaft zu manipulieren, um seinen Inhalt zu scrollen, indem ich den Wert VerticalScroll.Value änderte. Leider gibt es einige unerwünschte Nebeneffekte wie der Mausdaum in der Bildlaufleiste, der mit dem Inhalt des ScrollableControls nicht synchronisiert wird. Vielleicht liegt das daran, dass diese Arbeit innerhalb der Nachrichtenpumpe statt in einem Ereignishandler ausgeführt wird.

This post beschreibt eine Technik, bei der WM_MOUSEWHEEL-Nachrichten in ein anderes Fenster verschoben werden. Ich möchte ein IMessageFilter implementieren, das WM_MOUSEWHEEL Nachrichten abfängt, und sie an einen bestimmten Empfänger weiterleitet.

Ich erstelle die folgenden IMessageFilter, die dies versucht. Ich kann sehen, dass die weitergeleitete Nachricht von meinem Filter abgefangen wird, und ich gebe false aus dem Filter zurück, um dem Steuerelement mitzuteilen, dass es die Nachricht verarbeiten soll. Das Zielsteuerelement erhält kein OnMouseWheel Ereignis.

Kann dieser Filter geändert werden, damit meine targetControl mit umgeleiteten Nachrichten gescrollt werden kann?

public static class MouseWheelMessageRedirector 
{ 
    public static void Add(Control rootControl, ScrollableControl targetControl) 
    { 
     var filter = new MouseWheelMessageFilter(rootControl, targetControl); 
     Application.AddMessageFilter(filter); 

     rootControl.Disposed += (sender, args) => Application.RemoveMessageFilter(filter); 

     targetControl.MouseWheel += (sender, args) => 
     { 
      // ... this code never executes 
      System.Diagnostics.Trace.WriteLine("WHEEL ON TARGET"); 
     }; 
    } 

    private class MouseWheelMessageFilter : IMessageFilter 
    { 
     const int WM_MOUSEWHEEL = 0x020A; 

     [DllImport("user32.dll", SetLastError = true)] 
     static extern bool PostMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); 

     public MouseWheelMessageFilter(Control rootControl, ScrollableControl targetControl) 
     { 
      _rootControl = rootControl; 
      _targetControl = targetControl; 
      _targetWindowHandle = _targetControl.Handle; 
     } 

     public bool PreFilterMessage(ref Message m) 
     { 
      if (m.Msg != WM_MOUSEWHEEL) 
       return false; 

      if (m.HWnd == _targetWindowHandle) 
       return false; 

      // ... get the control that the mouse is over 
      // ... determine if this is a control that we want to handle the message for 
      // ... (omitted) 

      PostMessage(_targetWindowHandle, m.Msg, m.WParam, m.LParam); 
      return true; 
     } 

     private Control _rootControl; 
     private ScrollableControl _targetControl; 
     private IntPtr _targetWindowHandle; 
    } 
} 

Antwort

0

Ich habe gerade das Gleiche gemacht. Hier ist, was ich getan habe:

public bool PreFilterMessage(ref Message m) 
    { 
     if ((WM)m.Msg == WM.MOUSEWHEEL) 
     { 
      // if mouse is over a certain component, prevent scrolling 
      if (comboBoxVendors.Bounds.Contains(PointToClient(Cursor.Position))) 
      { 
       // return true which says the message is already processed 
       return true; 
      } 


      // which direction did they scroll? 
      int delta = 0; 
      if ((long)m.WParam >= (long)Int32.MaxValue) 
      { 
       var wParam = new IntPtr((long)m.WParam <<32>> 32); 
       delta = wParam.ToInt32() >> 16; 
      } 
      else 
      { 
       delta = m.WParam.ToInt32() >> 16; 
      } 

      delta = delta*-1; 
      var direction = delta > 0 ? 1 : 0; 

      // post message to the control I want scrolled (I am converting the vertical scroll to a horizontal, bu you could just re-send the same message to the control you wanted 
      PostMessage(splitContainerWorkArea.Panel2.Handle, Convert.ToInt32(WM.HSCROLL), (IntPtr) direction, IntPtr.Zero); 

      // return true to say that I handled the message 
      return true; 
     }       

     // message was something other than scroll, so ignore it 
     return false; 
    } 

Auch ich verwendet, um die Fenster Nachricht Enum von PInvoke.net: http://www.pinvoke.net/default.aspx/Enums.WindowsMessages

Schließlich sollten die Nachrichtenfilter entfernen, wenn Sie das Formular schließen, oder wenn Sie nicht länger müssen die Nachrichten verarbeiten:

Application.RemoveMessageFilter(thisForm) 
Verwandte Themen