11

私の C# 3.5 Windows Forms アプリケーションには、SplitContainers がいくつかあります。それぞれの内部にリスト コントロールがあります (ドック フィル)。これらのコントロールのいずれかにフォーカスがあり、マウス ホイールを動かすと、現在フォーカスされているリストがスクロールされます。

私の仕事は、選択されているリストではなく、現在マウスでホバーされているリストをスクロールすることです。Windowsフォームで可能ですか? そうでない場合、PInvoke で可能ですか?

4

4 に答える 4

8

IMessageFilterとPInvokeを使用してこれを処理できるようです。VBの例は、マウスホイールイベントをフォーカスされていないWindowsフォームコントロールにリダイレクトするにあります。これをC#に簡単に変換できるはずです。

興味がある点

このクラスは、特定のタスクに対して次の手法を使用します。

  • コントロールのMouseEnterイベントとMouseLeaveイベントをリッスンして、マウスポインターがコントロール上にあるときを判別します。
  • IMessageFilterを実装して、アプリケーションでWM_MOUSEWHEELメッセージをキャッチします。
  • PWindows API呼び出しSendMessageを呼び出して、WM_MOUSEWHEELメッセージをコントロールのハンドルにリダイレクトします。
  • IMessageFilterオブジェクトは、MouseWheelRedirectorクラスのシングルトンとして実装され、共有メンバーのAttach、Detach、およびActiveによってアクセスされます。

VB.NETからC#へのコンバーターを使用すると、次のようになります。

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);
 }
于 2012-06-14T13:55:47.983 に答える
6

私は同様の質問をしてこのスレッドを見つけました...それで、このスレッドを見つけるかもしれない他の人のために私の遅れた答えを投稿してください。私の場合、マウスホイールイベントをカーソルの下にあるコントロールに移動させたいだけです...右クリックと同じように(右クリックでカーソルの下のコントロールではなくフォーカスコントロールに移動すると、戸惑うでしょう) ...私たちがそれに慣れていることを除いて、同じことがマウスホイールにも当てはまると私は主張します)。

とにかく、答えはとても簡単です。PreFilterMessageをアプリケーションに追加し、マウスホイールイベントをマウスの下のコントロールにリダイレクトするだけです。

    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; 
           } 
}
于 2012-11-08T16:08:53.357 に答える
3

Control.MouseEnter イベントを使用して、フォーカスをコントロールに設定します。たとえば、ActiveControl プロパティを使用する

于 2012-06-14T13:49:14.063 に答える