Windows 10 1803下WPF透明窗口覆盖致其他应用触摸/笔输入失效问题
问题原因分析
这个问题是Windows 10 1803(10.0.17134.0)版本的WPF框架存在的特定bug导致的:当你创建一个同时满足AllowsTransparency="True"、Topmost="True"、无边框最大化的窗口时,系统错误地将整个透明窗口区域标记为可接收触摸/笔输入的区域,拦截了所有原本应该传递给下方应用的触摸/笔事件——哪怕窗口背景是完全透明的。这就导致下方应用的StylusDown等触摸相关事件无法触发,直到关闭这个置顶透明窗口。
解决方法
下面提供几种可行的解决方案,你可以根据自己的需求选择:
方案1:重写窗口的命中测试逻辑,仅让非透明控件接收输入
通过重写窗口的HitTestCore方法,我们可以让窗口的透明区域忽略输入命中测试,这样系统就会把触摸/笔事件传递给下方的应用,同时窗口内的控件(比如你的Test按钮)依然能正常响应输入。
在你的WPF窗口类中添加以下代码:
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParams) { // 先执行默认的命中测试 var defaultResult = base.HitTestCore(hitTestParams); // 如果命中的是透明区域或者不可点击的元素,返回null让输入穿透 if (defaultResult == null || !((Visual)defaultResult.VisualHit).IsHitTestVisible) { return null; } return defaultResult; }
方案2:设置窗口扩展样式实现输入穿透
通过Windows API给窗口添加WS_EX_TRANSPARENT扩展样式,这个样式会让整个窗口忽略所有鼠标/触摸输入,直接将事件传递给下方的窗口。不过要注意,这种方式下窗口内的控件也会失去输入响应,如果你的窗口不需要交互,这个方法非常简单。
在窗口类中添加以下代码:
using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; public partial class MainWindow : Window { private const int WS_EX_TRANSPARENT = 0x00000020; private const int GWL_EXSTYLE = -20; [DllImport("user32.dll")] private static extern int GetWindowLong(IntPtr hwnd, int index); [DllImport("user32.dll")] private static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle); protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); // 获取窗口句柄 var hwnd = new WindowInteropHelper(this).Handle; // 获取当前扩展样式 var currentExStyle = GetWindowLong(hwnd, GWL_EXSTYLE); // 添加WS_EX_TRANSPARENT样式 SetWindowLong(hwnd, GWL_EXSTYLE, currentExStyle | WS_EX_TRANSPARENT); } }
方案3:升级Windows系统版本
这个bug在Windows 10 1809及以后的版本中已经被微软修复了,如果你的使用场景允许升级系统,这是最彻底的解决方案,不需要修改任何代码就能解决问题。
内容的提问来源于stack exchange,提问作者walterlv
相关产品推荐
相关产品推荐

