c# – 拖动时可以使用鼠标滚轮吗?

前端之家收集整理的这篇文章主要介绍了c# – 拖动时可以使用鼠标滚轮吗?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在WinForms中,在调用DoDragDrop开始拖动项目后,控件不再使用鼠标滚轮进行滚动,并且控件的MouseWheel事件不再被调用,直到用户放下任何拖动的东西.

拖动鼠标滚轮是否有办法?

解决方法

您可以使用键盘钩子获取全局MouseWheel.
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.Win32.SafeHandles;

using BOOL = System.Boolean;
using DWORD = System.UInt32;
using HHOOK = SafeHookHandle;
using HINSTANCE = System.IntPtr;
using HOOKPROC = HookProc;
using LPARAM = System.IntPtr;
using LRESULT = System.IntPtr;
using POINT = System.Drawing.Point;
using ULONG_PTR = System.IntPtr;
using WPARAM = System.IntPtr;

public delegate LRESULT HookProc(int nCode,WPARAM wParam,LPARAM lParam);

internal static class NativeMethods
{
    [DllImport("User32.dll",SetLastError = true)]
    internal static extern HHOOK SetWindowsHookEx(
        HookType idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadId);

    [DllImport("User32.dll")]
    internal static extern LRESULT CallNextHookEx(
        HHOOK hhk,int nCode,LPARAM lParam);

    [DllImport("User32.dll",SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern BOOL UnhookWindowsHookEx(
        IntPtr hhk);

    [DllImport("kernel32.dll",CharSet = CharSet.Auto)]
    public static extern IntPtr GetModuleHandle(string lpModuleName);
}

internal static class NativeTypes
{
    internal enum MSLLHOOKSTRUCTFlags : uint
    {
        LLMHF_INJECTED = 0x00000001U,}

    [StructLayout(LayoutKind.Sequential)]
    internal struct MSLLHOOKSTRUCT
    {
        internal POINT pt;
        internal DWORD mouseData;
        internal MSLLHOOKSTRUCTFlags flags;
        internal DWORD time;
        internal ULONG_PTR dwExtraInfo;
    }
}

internal static class NativeConstants
{
    internal const int WH_MOUSE_LL = 14;

    internal const int HC_ACTION = 0;

    internal const int WM_MOUSEWHEEL = 0x020A;
    internal const int WM_MOUSEHWHEEL = 0x020E;

    internal const int WHEEL_DELTA = 120;
}

public enum HookType
{
    LowLevelMouseHook = NativeConstants.WH_MOUSE_LL
}

public enum HookScope
{
    LowLevelGlobal,}

public class SafeHookHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    private SafeHookHandle() : base(true) { }

    public static SafeHookHandle SetWindowsHook(HookType idHook,HookProc lpfn,IntPtr hMod,uint dwThreadId)
    {
        var hhk = NativeMethods.SetWindowsHookEx(idHook,lpfn,hMod,dwThreadId);

        if(hhk.IsInvalid)
        {
            throw new Win32Exception();
        }
        else
        {
            return hhk;
        }
    }

    public IntPtr CallNextHook(int nCode,IntPtr wParam,IntPtr lParam)
    {
        return NativeMethods.CallNextHookEx(this,nCode,wParam,lParam);
    }

    protected override bool ReleaseHandle()
    {
        return NativeMethods.UnhookWindowsHookEx(this.handle);
    }
}

public abstract class WindowsHook : IDisposable
{
    private SafeHookHandle hhk;
    private HookProc lpfn;

    protected WindowsHook(HookType idHook,HookScope scope)
    {
        this.lpfn = this.OnWindowsHook;

        switch(scope)
        {
            case HookScope.LowLevelGlobal:
                IntPtr moduleHandle = NativeMethods.GetModuleHandle(null);
                this.hhk = SafeHookHandle.SetWindowsHook(idHook,this.lpfn,moduleHandle,0U);
                return;
            default:
                throw new InvalidEnumArgumentException("scope",(int)scope,typeof(HookScope));
        }
    }

    protected virtual IntPtr OnWindowsHook(int nCode,IntPtr lParam)
    {
        return this.hhk.CallNextHook(nCode,lParam);
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if(disposing)
        {
            if(this.hhk != null) { this.hhk.Dispose(); }
        }
    }
}

public class LowLevelMouseHook : WindowsHook
{
    public event MouseEventHandler MouseWheel;

    public LowLevelMouseHook() : base(HookType.LowLevelMouseHook,HookScope.LowLevelGlobal) { }

    protected sealed override IntPtr OnWindowsHook(int nCode,IntPtr lParam)
    {
        if(nCode == NativeConstants.HC_ACTION)
        {
            var msLLHookStruct = (NativeTypes.MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam,typeof(NativeTypes.MSLLHOOKSTRUCT));

            switch(wParam.ToInt32())
            {
                case NativeConstants.WM_MOUSEWHEEL:
                case NativeConstants.WM_MOUSEHWHEEL:
                    this.OnMouseWheel(new MouseEventArgs(Control.MouseButtons,msLLHookStruct.pt.X,msLLHookStruct.pt.Y,(int)msLLHookStruct.mouseData >> 16));
                    break;
            }
        }

        return base.OnWindowsHook(nCode,lParam);
    }

    protected virtual void OnMouseWheel(MouseEventArgs e)
    {
        if(this.MouseWheel != null)
        {
            this.MouseWheel(this,e);
        }
    }
}

样品用法

using (LowLevelMouseHook hook = new LowLevelMouseHook())
{
    hook.MouseWheel += (sender,e) =>
    {
        Console.WriteLine(e.Delta);
    };
    Application.Run();
}

代码提供了一个类LowLevelMouseHook,其中包含事件MouseWheel,其行为类似于内建窗体控件类的事件.

(此外,代码分为一个抽象类WindowsHooks,用于其他钩子,一个SafeHookHandle类以确保句柄被释放,并且本机方法的辅助类)

你应该看看SetWindowsHookExCALLBACK LowLevelMouseProc了解这个背后的技术.

此事件不仅限于您的应用程序,而且还将捕获表单外的鼠标,因此它也适用于您不能使用本地事件的操作.

猜你在找的C#相关文章