C# · 12月 27, 2021

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类以确保句柄被释放,并且本机方法的辅助类)

你应该看看SetWindowsHookEx和CALLBACK LowLevelMouseProc了解这个背后的技术.

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