Как пересылать сообщения (например, колесо мыши) другому элементу управления без кражи фокуса и без P / Invoke?

Я хочу переслать сообщение (например, WM_MOUSEWHEEL), когда я нахожусь над этим элементом управления с помощью мыши, без кражи фокуса. Эта проблема может быть легко решена путем перехвата сообщения с помощью IMessageFilter (который должен быть добавлен в насос сообщений приложения) и пересылки его с помощью P / Invoke (d) SendMessage (). Вопрос в том: Могу ли я сделать то же самое без использования P / Invoke (решения, которые я нашел в StackOverflow, используют P / Invoke)? Если нет, то почему?

Приведенный ниже код является моим решением с P / Invoke. Я использую его только с new MessageForwarder (control, 0x20A) .

/// <summary>
/// This class implements a filter for the Windows.Forms message pump allowing a
/// specific message to be forwarded to the Control specified in the constructor.
/// Adding and removing of the filter is done automatically.
/// </summary>
public class MessageForwarder : IMessageFilter
{
#region Fields

private Control _Control;
private Control _PreviousParent;
private HashSet<int> _Messages;
private bool _IsMouseOverControl;

#endregion // Fields

#region Constructors

public MessageForwarder(Control control, int message)
    : this(control, new int[] { message }) { }

public MessageForwarder(Control control, IEnumerable<int> messages)
{
    _Control = control;
    _Messages = new HashSet<int>(messages);
    _PreviousParent = control.Parent;
    _IsMouseOverControl = false;

    control.ParentChanged += new EventHandler(control_ParentChanged);
    control.MouseEnter += new EventHandler(control_MouseEnter);
    control.MouseLeave += new EventHandler(control_MouseLeave);
    control.Leave += new EventHandler(control_Leave);

    if (control.Parent != null)
        Application.AddMessageFilter(this);
}

#endregion // Constructors

#region IMessageFilter members

public bool PreFilterMessage(ref Message m)
{
    if (_Messages.Contains(m.Msg) && _Control.CanFocus && !_Control.Focused
        && _IsMouseOverControl)
    {
        SendMessage(_Control.Handle, m.Msg, m.WParam, m.LParam);
        return true;
    }

    return false;
}

#endregion // IMessageFilter

#region Event handlers

void control_ParentChanged(object sender, EventArgs e)
{
    if (_Control.Parent == null)
        Application.RemoveMessageFilter(this);
    else
    {
        if (_PreviousParent == null)
            Application.AddMessageFilter(this);
    }
    _PreviousParent = _Control.Parent;
}

void control_MouseEnter(object sender, EventArgs e)
{
    _IsMouseOverControl = true;
}

void control_MouseLeave(object sender, EventArgs e)
{
    _IsMouseOverControl = false;
}

void control_Leave(object sender, EventArgs e)
{
    _IsMouseOverControl = false;
}

#endregion // Event handlers

#region Support

[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

#endregion // Support

}

EDIT : полное решение в моем ответе

6
задан ceztko 3 March 2018 в 09:02
поделиться