Вопрос по winforms, c#, mousewheel, scroll – Событие колеса мыши для работы с наведённым управлением

10

В моем приложении Windows Forms C # 3.5 у меня есть несколько SplitContainers. Внутри каждого есть элемент управления списком (заполнение дока). Когда фокус находится на одном из этих элементов управления, и я перемещаю колесо мыши, список, который теперь сфокусирован, прокручивается.

Моя задача - прокрутить список, который в данный момент наведен мышью, а не тот, который выбран. Возможно ли это в Windows Forms? Если нет, возможно ли это с помощью PInvoke?

Кажется, они заставили «прокручивать любой курсор мыши над» стандартное поведение в Windows 10. Что на самом деле раздражает в большинстве случаев. Nyerguds

Ваш Ответ

4   ответа
3

Событие Control.MouseEnter установить фокус на элемент управления. Например. с помощьюActiveControl Property

Иногда удобно прокрутить элемент управленияwithout фокусировка, например, если она отводит фокус от текстового поля.
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; 
           } 
}
Здесь немного не хватает этого. Вам нужно DllImport WindowFromPoint () и SendMessage:[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);  Кроме того, PreFilterMessage () происходит из IMessageFilter, и эту реализацию необходимо передатьApplicationAddMessageFilter(), После этого все панели моего приложения стали прокручиваться под мышью. Однако двойной щелчок больше не выделяет текст. Странный.
9

IMessageFilter и PInvoke, чтобы справиться с этим. Пример в VB можно найти наПеренаправить события колеса мыши на несосредоточенные элементы управления Windows Forms, Вы должны быть в состоянии легко конвертировать это в C #.

Точки интереса

Этот класс использует следующие методы для данной задачи:

Listen to the control's MouseEnter and MouseLeave events to determine when the mouse pointer is over the control. Implement IMessageFilter to catch WM_MOUSEWHEEL messages in the application. PInvoke the Windows API call SendMessage redirecting the WM_MOUSEWHEEL message to the control's handle. The IMessageFilter object is implemented as a singleton of the MouseWheelRedirector class and accessed by the shared members Attach, Detach, and 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);
 }
@ blackholeearth0_gmail Гм. Как я прокомментировал сам вопрос надthree years назад, это все не имеет отношения к Windows 10, так как прокрутка наведенного управления являетсяdefault behaviour на win10. Вы даже неneed любой из этого кода; это просто работает в любом случае.
Хм. Похоже, что NumericUpDown не хочет это слушать.
Вам нужно будет добавить обработчики к & apos; PreFilterMessage & apos; которые могут передавать сенсорную панель или цифровые кнопки навигации. В настоящее время он передает только сообщения с колесом прокрутки.
Это не работает с большинством сенсорных панелей, используя такие методы, как правая или двойная прокрутка пальцем. Похоже, что их драйверы делают какую-то черную магию, чтобы отправлять сообщения прокрутки прямо на полосы прокрутки элемента управления вместо отправкиWM_MOUSEWHEEL на контроль, как они должны. Любые идеи о том, как обойти это?
@ Nyerguds. это работает на win 10. также правый край или двойной палец прокрутки. Вы проверили в веб-браузере, как ff60. нажмите на адресную строку. затем наведите курсор мыши на веб-страницу. попробуйте выполнить прокрутку с помощью правого или двойного пальца. если они также не работают в браузере, то вам нужно установить драйвер сенсорной панели. включить зависание прокрутки для указанного элемента управленияform1_load {MouseWheelRedirector .attach(panel1); }
3

Brian Kennedyответ завершенHank Schultz комментарий:

Сначала вы должны сделать класс реализует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;
        }
    }
}

Пример использования:

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

Похожие вопросы