如何禁用WinForm禁用窗体点击时的Windows Ding提示音
解决WinForm通知窗体点击触发Ding提示音的问题
当窗体设置为Enabled = false时,点击会触发系统错误提示音,这是因为系统判定你在尝试与不可交互的控件交互。我们可以通过拦截窗口消息,让窗体完全忽略鼠标输入,同时保持不可激活、置于后台的状态,彻底避免提示音问题。
解决方案
- 重写
WndProc方法,拦截WM_MOUSEACTIVATE消息,返回MA_NOACTIVATE阻止窗体被激活 - 拦截
WM_NCHITTEST消息,返回HTTRANSPARENT让鼠标点击穿透到下层窗口,当前窗体不会收到任何鼠标相关响应 - 移除
Enabled = false设置,改用消息拦截实现不可交互效果
修改后的完整代码
using System.Runtime.InteropServices; namespace Background_Notes; public partial class Note : Form { [DllImport("user32.dll")] static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); static readonly IntPtr HwndBottom = new IntPtr(1); const UInt32 SwpNosize = 0x0001; const UInt32 SwpNomove = 0x0002; const UInt32 SwpNoactivate = 0x0010; // 窗口消息常量 private const int WM_MOUSEACTIVATE = 0x0021; private const int WM_NCHITTEST = 0x0084; private const int MA_NOACTIVATE = 0x0003; private const int HTTRANSPARENT = -1; public Note() { InitializeComponent(); ShowInTaskbar = false; FormBorderStyle = FormBorderStyle.None; SetStyle(ControlStyles.Selectable, false); TextBox t = new TextBox(); t.Width = 200; t.Text = "This is a notification!"; Controls.Add(t); Show(); SetWindowPos(Handle, HwndBottom, 0, 0, 0, 0, SwpNomove | SwpNosize | SwpNoactivate); } protected override bool ShowWithoutActivation => true; protected override void WndProc(ref Message m) { switch (m.Msg) { // 阻止窗体被鼠标激活 case WM_MOUSEACTIVATE: m.Result = new IntPtr(MA_NOACTIVATE); return; // 让鼠标点击穿透到下层窗口 case WM_NCHITTEST: m.Result = new IntPtr(HTTRANSPARENT); return; } base.WndProc(ref m); } }
关键代码说明
WM_MOUSEACTIVATE:鼠标点击窗体时系统发送此消息,返回MA_NOACTIVATE告知系统无需激活当前窗体WM_NCHITTEST:系统通过此消息判断鼠标位置对应的窗口区域,返回HTTRANSPARENT会让点击事件直接传递给下层窗口,当前窗体不会触发任何鼠标相关响应(包括提示音)- 移除
Enabled = false后,窗体本身处于启用状态,但消息拦截机制会让它完全不响应用户输入,同时规避了系统错误提示音
内容的提问来源于stack exchange,提问作者Caspar
相关产品推荐
相关产品推荐

