WPF程序在触摸失效时的解决方案
在使用触摸屏幕的系统中,当WPF程序在创建并Show
窗口的时候,如果窗口的加载过程中有高负荷的CPU使用操作(在性能低下的主机中尤为如此),则窗口在显示完成后有一定几率会触摸失效。其表现为任何触摸的操作都没有反应,但鼠标可以正常的操作,这种情况也会在触摸屏硬件断开并重新连接后出现。
失效的这一现象只出现在你的程序中,而其他程序或者系统程序则触摸正常。此问题是属于 .NET Framework 的底层的缺陷,且这一问题直到微软推出了最后的版本4.8也没有解决。要处理这一问题,可以在加载窗口的过程中尽量少做操作,将操作放到窗口加载后来执行,但这只是降低出现的概率并不能根治。
一、 降级修复方案
针对此问题有一个较为可靠的降级修复方案,停用运行时框架自带的手写笔支持,将触控输入切换到普通多点触控模式,并手动构建触摸消息,由此来达到偷梁换柱的操作。该操作的实现原理来源于官方的文档介绍,为 WPF 应用程序禁用 RealTimeStylus。该文档有描述:
Windows Presentation Foundation (WPF) 内置了对处理 Windows 7 触摸输入的支持。这种支持来自平板电脑平台的实时触笔输入,如OnStylusDown、OnStylusUp和OnStylusMove事件。Windows 7 还提供多点触控输入作为 Win32 WM_TOUCH 窗口消息。这两个 API 在同一个 HWND 上是互斥的。通过平板电脑平台启用触摸输入(WPF 应用程序的默认设置)会禁用 WM_TOUCH 消息。因此,要使用 WM_TOUCH 从 WPF 窗口接收触摸消息,您必须禁用 WPF 中的内置触控笔支持。这适用于托管使用 WM_TOUCH 的组件的 WPF 窗口等场景。
1、 禁用手写笔支持
前方的文档给出了说明并同时给出了示例代码,使用其反射来禁用默认的触笔支持。
public static void DisableWPFTabletSupport()
{
// Get a collection of the tablet devices for this window.
TabletDeviceCollection devices = System.Windows.Input.Tablet.TabletDevices;
if (devices.Count > 0)
{
// Get the Type of InputManager.
Type inputManagerType = typeof(System.Windows.Input.InputManager);
// Call the StylusLogic method on the InputManager.Current instance.
object stylusLogic = inputManagerType.InvokeMember("StylusLogic",
BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
null, InputManager.Current, null);
if (stylusLogic != null)
{
// Get the type of the stylusLogic returned from the call to StylusLogic.
Type stylusLogicType = stylusLogic.GetType();
// Loop until there are no more devices to remove.
while (devices.Count > 0)
{
// Remove the first tablet device in the devices collection.
stylusLogicType.InvokeMember("OnTabletRemoved",
BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic,
null, stylusLogic, new object[] { (uint)0 });
}
}
}
}
在经过以上的操作后,运行时默认的手写笔支持已经被禁用,同时触摸层也受到该操作影响。