在使用触摸屏幕的系统中,当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 });  
            }
        }  
    }  
}

  在经过以上的操作后,运行时默认的手写笔支持已经被禁用,同时触摸层也受到该操作影响。