Dot-Net

在 Windows 8 下,觸摸 WPF 按鈕有時不會呼叫點擊處理程序

  • September 25, 2019

“當應用程序視窗沒有焦點時,有時點擊處理程序不會在按鈕觸摸時呼叫。”

系統:

帶有多點觸控輸入設備的 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.StylusLogic 的PromoteMainToMouse() 函式中。

我真的沒有想法要檢查什麼。因此,如果有人能給我建議要測試什麼或在 .net 中設置斷點的位置以找到根本原因,那就太好了。或者甚至更好地找到解決方案/解決方法。

更新:

我發現如果滑鼠指針剛剛離開應用程序視窗(至少在我們的平台上),我也可以重現這種現象。發生錯誤的可能性似乎隨著使用者界面的複雜性而增加——我的測試應用程序並非總是無法辨識點擊,但複雜的 WPF 應用程序每次都會失敗。

您應該能夠在帶有觸摸設備的 Windows 8.1 上使用 WPF 開發人員工作室(例如 2013 版)重現它:

  • 讓開發人員工作室打開以僅覆蓋觸摸屏的一半
  • move away 移動使游標指向桌面區域
  • 觸摸一個按鈕(例如“開始調試”——播放按鈕):在我的情況下,第一次觸摸永遠不會導致點擊事件。

原來是WPF中的一個BUG。在發布 KB 之前,有一種解決方法可用。

解決方法是呼叫MainWindow 受影響的 UIElementMouse.Synchronize();PreviewTouchDown事件處理程序。

我測試了它,它工作正常。

我遇到了同樣的問題,發現禁用 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 });  
           }                  
       }  

   }  
}  

引用自:https://stackoverflow.com/questions/28441538