如何避免WPF弹窗在触摸键盘弹出时自动关闭?
解决WPF Popup因触摸键盘弹出而意外关闭的问题
核心思路
通过Windows API检测当前激活的窗口是否为系统触摸键盘(OSK),在Popup即将因失去焦点关闭时,若判断是触摸键盘导致的焦点转移,则阻止Popup关闭;其他情况保持原有的“失去焦点即关闭”行为。
实现步骤
1. 导入Windows API函数
在窗口类中添加以下DllImport声明,用于获取当前激活窗口及其类名:
using System.Runtime.InteropServices; using System.Text; // 获取前台窗口句柄 [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); // 获取指定窗口的类名 [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
2. 编写触摸键盘检测方法
添加辅助方法判断当前激活窗口是否为系统触摸键盘:
private bool IsOnScreenKeyboardActive() { const int maxClassNameLength = 256; var classNameBuilder = new StringBuilder(maxClassNameLength); IntPtr activeWindowHandle = GetForegroundWindow(); // 获取当前激活窗口的类名 if (GetClassName(activeWindowHandle, classNameBuilder, maxClassNameLength) > 0) { // 系统触摸键盘的固定窗口类名为 "IPTip_Main_Window" return classNameBuilder.ToString() == "IPTip_Main_Window"; } return false; }
3. 拦截Popup的焦点丢失事件
修改Popup的PreviewLostKeyboardFocus事件处理逻辑,结合检测结果控制Popup状态:
private void Popup_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { var popup = (Popup)sender; if (IsOnScreenKeyboardActive()) { // 焦点转移到触摸键盘时,阻止事件传递并强制保持Popup打开 e.Handled = true; popup.StaysOpen = true; } else { // 其他情况恢复原行为,允许Popup关闭 popup.StaysOpen = false; } }
4. 补充外部点击关闭逻辑
为确保点击非触摸键盘区域时Popup正常关闭,添加PreviewMouseDownOutsideCapturedElement事件处理:
private void Popup_PreviewMouseDownOutsideCapturedElement(object sender, MouseButtonEventArgs e) { ((Popup)sender).IsOpen = false; }
注意事项
- 初始需将Popup的
StaysOpen属性设为False,保证基础的失去焦点关闭行为。 - 触摸键盘的窗口类名在主流Windows版本中均为
IPTip_Main_Window,若后续系统版本变更需同步调整该值。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

