【问题标题】:Touching a WPF button does sometimes not invoke the click handler under Windows 8在 Windows 8 下,触摸 WPF 按钮有时不会调用单击处理程序
【发布时间】:2019-09-25 22:03:18
【问题描述】:

“当应用程序窗口没有焦点时,有时点击处理程序不会在按钮触摸时调用。”

系统:

带有多点触控输入设备的 Windows 8.1。

软件:

一个简单的 WPF 4.5.2 应用程序,只有一个按钮来记录是否调用了单击处理程序(只需创建一个新项目并将一个带有单击处理程序的按钮添加到 MainWindow)。

现象:

通常在触摸按钮时会调用其单击处理程序。 但是当应用程序窗口没有焦点时,有时点击处理程序不会在按钮触摸时调用(尽管按钮颜色变为蓝色)。当应用程序窗口已经获得焦点时,触摸按钮一直有效。 这种情况有时会发生,但会发生在具有不同触摸硬件的各种系统上(所有 Windows 8.1)。我从未在 Windows 7 上体验过。 无论窗口是否聚焦,鼠标都可以工作。

(在发布和调试模式下发生,附带和不附带调试器)

测试:

我检查了 Windows 中的各种触摸设置并开始使用它。我还重新校准了触摸 -> 没有区别。

在检查 WPF 按钮鼠标和触摸事件时,在错误情况下,最后收到的事件是 PreviewMouseUp 但没有 Click!

当我查看收到的窗口消息 (spy++) 时,我得到以下信息(WM_IME_SETCONTEXT、WM_GETTEXT、WM_NCHITTEST、WM_GETOBJECT 被删除以获得更好的概览):

收到点击:

R WM_POINTERACTIVATE pmsd->lResult:FFFFFFFFFFFFFFFF
S WM_MOUSEACTIVATE hwndTopLevel:000503F8 nHittest:HTCLIENT uMsg:WM_POINTERDOWN
R WM_MOUSEACTIVATE fuActivate:MA_ACTIVATE
S WM_WINDOWPOSCHANGING lpwp:000000E9E3D9E410
R WM_WINDOWPOSCHANGING
S WM_WINDOWPOSCHANGED lpwp:000000E9E3D9E410
R WM_WINDOWPOSCHANGED
S WM_ACTIVATEAPP fActive:True dwThreadID:00000000
R WM_ACTIVATEAPP
S WM_NCACTIVATE fActive:True
R WM_NCACTIVATE
S WM_ACTIVATE fActive:WA_ACTIVE fMinimized:False hwndPrevious:(null)
S WM_IME_NOTIFY dwCommand:IMN_OPENSTATUSWINDOW dwCommand:00000002 dwData:00000000
R WM_IME_NOTIFY
S WM_SETFOCUS hwndLoseFocus:(null)
R WM_SETFOCUS
R WM_ACTIVATE
S message:0x02CC [Unknown] wParam:00000000 lParam:00C50BA8
R message:0x02CC [Unknown] lResult:00000100
P WM_POINTERENTER wPointerID:0099 wFlags:6017
S WM_SETCURSOR hwnd:000503F8 nHittest:HTCLIENT wMouseMsg:WM_LBUTTONDOWN
R WM_SETCURSOR fHaltProcessing:False
P WM_LBUTTONDOWN fwKeys:MK_LBUTTON xPos:145 yPos:62
R WM_POINTERCAPTURECHANGED
P WM_MOUSEMOVE fwKeys:MK_LBUTTON xPos:145 yPos:62
P WM_POINTERLEAVE wPointerID:0099 wFlags:6000
P WM_LBUTTONUP fwKeys:0000 xPos:145 yPos:62
P WM_MOUSEMOVE fwKeys:0000 xPos:145 yPos:62
S WM_CAPTURECHANGED hwndNewCapture:000503F8
R WM_CAPTURECHANGED
S WM_CAPTURECHANGED hwndNewCapture:00000000
R WM_CAPTURECHANGED
S WM_SETCURSOR hwnd:000503F8 nHittest:HTCLIENT wMouseMsg:WM_MOUSEMOVE
R WM_SETCURSOR fHaltProcessing:False
P WM_MOUSEMOVE fwKeys:0000 xPos:145 yPos:62

未收到点击

S message:0x02CC [Unknown] wParam:00000000 lParam:00AE0BA9
R message:0x02CC [Unknown] lResult:00000100
R WM_POINTERACTIVATE pmsd->lResult:FFFFFFFFFFFFFFFF
S WM_MOUSEACTIVATE hwndTopLevel:000503F8 nHittest:HTCLIENT uMsg:WM_POINTERDOWN
R WM_MOUSEACTIVATE fuActivate:MA_ACTIVATE
S WM_WINDOWPOSCHANGING lpwp:000000E9E3D9E410
R WM_WINDOWPOSCHANGING
S WM_WINDOWPOSCHANGED lpwp:000000E9E3D9E410
R WM_WINDOWPOSCHANGED
S WM_ACTIVATEAPP fActive:True dwThreadID:00000000
R WM_ACTIVATEAPP
S WM_NCACTIVATE fActive:True
R WM_NCACTIVATE
S WM_ACTIVATE fActive:WA_ACTIVE fMinimized:False hwndPrevious:(null)
S WM_IME_NOTIFY dwCommand:IMN_OPENSTATUSWINDOW dwCommand:00000002 dwData:00000000
R WM_IME_NOTIFY
S WM_SETFOCUS hwndLoseFocus:(null)
R WM_SETFOCUS
R WM_ACTIVATE
P WM_POINTERENTER wPointerID:0090 wFlags:6017
S WM_SETCURSOR hwnd:000503F8 nHittest:HTCLIENT wMouseMsg:WM_LBUTTONDOWN
R WM_SETCURSOR fHaltProcessing:False
P WM_LBUTTONDOWN fwKeys:MK_LBUTTON xPos:147 yPos:39
R WM_POINTERCAPTURECHANGED
S WM_SETCURSOR hwnd:000503F8 nHittest:HTCLIENT wMouseMsg:WM_MOUSEMOVE
R WM_SETCURSOR fHaltProcessing:False
P WM_MOUSEMOVE fwKeys:MK_LBUTTON xPos:147 yPos:39
P WM_POINTERLEAVE wPointerID:0090 wFlags:6000
S WM_SETCURSOR hwnd:000503F8 nHittest:HTCLIENT wMouseMsg:WM_LBUTTONUP
R WM_SETCURSOR fHaltProcessing:False
P WM_LBUTTONUP fwKeys:0000 xPos:147 yPos:39
S WM_SETCURSOR hwnd:000503F8 nHittest:HTCLIENT wMouseMsg:WM_MOUSEMOVE
R WM_SETCURSOR fHaltProcessing:False
P WM_MOUSEMOVE fwKeys:0000 xPos:147 yPos:39
S WM_SETCURSOR hwnd:000503F8 nHittest:HTCLIENT wMouseMsg:WM_MOUSEMOVE
R WM_SETCURSOR fHaltProcessing:False
P WM_MOUSEMOVE fwKeys:0000 xPos:147 yPos:39
S WM_SETCURSOR hwnd:000503F8 nHittest:HTCLIENT wMouseMsg:WM_MOUSEMOVE
R WM_SETCURSOR fHaltProcessing:False
P WM_MOUSEMOVE fwKeys:0000 xPos:147 yPos:39

在错误中有额外的行

S WM_SETCURSOR hwnd:000503F8 nHittest:HTCLIENT wMouseMsg:WM_LBUTTONUP
R WM_SETCURSOR fHaltProcessing:False

在 WM_LBUTTONUP 之前。但我不知道这是否有关系。

我已经尝试调试 .net 代码以查看导致不调用 Click 处理程序的条件,但我很快就迷失在 System.Windows.Input.InputManager 和 System.Windows.Input 的 PromoteMainToMouse() 函数中。 StylusLogic。

我实在想不出要检查什么了。 因此,如果有人能给我建议要测试什么或在 .net 中设置断点的位置以找到根本原因,那就太好了。或者更好地找到解决方案/解决方法。

更新:

我发现如果鼠标指针刚刚离开应用程序窗口(至少在我们的平台上),我也可以重现这种现象。而且发生错误的可能性似乎随着用户界面的复杂性而增加——我的测试应用程序并非总是无法识别点击,但复杂的 WPF 应用程序每次都会失败。

您应该能够在带有触摸设备的 Windows 8.1 上使用 WPF 开发人员工作室(例如 2013 版)重现它:

  • 打开开发者工作室,只覆盖一半的触摸屏
  • 移开移动使光标指向桌面区域
  • 触摸一个按钮(例如“开始调试” - 播放按钮):在我的情况下,第一次触摸永远不会导致点击事件。

【问题讨论】:

    标签: .net wpf touch windows-8.1


    【解决方案1】:

    原来是 WPF 中的一个 BUG。在 KB 发布之前,有一种解决方法可用。

    解决方法是在 MainWindow 的受影响 UIElement 的 PreviewTouchDown 事件处理程序中调用 Mouse.Synchronize();

    我测试了它,它工作正常。

    【讨论】:

    【解决方案2】:

    我遇到了同样的问题,发现禁用 RealTimeStylus(有效地禁用触摸支持)对我有用,并导致鼠标事件总是在触摸时引发。

    我们在 Windows 10 上使用支持多点触控的工业触摸屏。

    https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/disable-the-realtimestylus-for-wpf-applications

    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 });  
                }                  
            }  
    
        }  
    }  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-23
      • 1970-01-01
      • 1970-01-01
      • 2014-04-07
      • 2023-03-08
      • 2011-04-01
      • 2012-10-20
      • 1970-01-01
      相关资源
      最近更新 更多