2016-04-15 22 views
1

WM_MOUSEWHEELメッセージは、フォーカスを持つコントロールに送信されます。私のアプリケーションには複雑なコントロール階層があり、コントロールには他のコントロールが含まれており、その中には見えないものや重なっているものがあります。特定のスクロールするマウスホイールを希望しますScrollableControlマウスホイールのメッセージをあるウィンドウから別のウィンドウにリダイレクトするにはどうすればよいですか?

This questionIMessageFilterの実装ではWM_MOUSEWHEELのメッセージをキャッチします。これは正常に動作し、私はメッセージがキャッチされて参照してください。私はVerticalScroll.Valueの値を変更して、その内容をスクロールするScrollableControlのVerticalScrollプロパティを操作しようとしました。残念ながら、ScrollableControlの内容と同期しなくなるような、スクロールバーのマウスの親指のような望ましくない副作用があります。おそらくこれは、この作業がイベントハンドラではなくメッセージポンプ内で実行されているためです。

This postには、WM_MOUSEWHEELメッセージが別のウィンドウに再送信される技術が記載されています。私はIMessageFilterを実装して、WM_MOUSEWHEELメッセージをキャッチし、それらを指定された受信者に転送したいと考えています。

私はこれをしようとする次のIMessageFilterを作成します。私は転送されたメッセージが自分のフィルターで捕捉されているのを見ることができ、私はフィルターからfalseを返して、メッセージを処理するようにコントロールに指示します。ターゲットコントロールは、OnMouseWheelイベントを受信しません。

リダイレクトされたメッセージを使用してtargetControlをスクロールできるようにこのフィルタを変更できますか?

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

答えて

0

私はこの同じことをしました。ここに私がやったことだ:最後に、フォームを閉じるときにメッセージフィルタを削除してください http://www.pinvoke.net/default.aspx/Enums.WindowsMessages

とき、またはあなたなし:

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

はまた、私はPInvoke.netからのウィンドウメッセージの列挙型を使用メッセージを処理するのに時間がかかる:

Application.RemoveMessageFilter(thisForm) 
関連する問題