在 Windows 8 下,觸摸 WPF 按鈕有時不會呼叫點擊處理程序
“當應用程序視窗沒有焦點時,有時點擊處理程序不會在按鈕觸摸時呼叫。”
系統:
帶有多點觸控輸入設備的 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 受影響的 UIElement
Mouse.Synchronize();的PreviewTouchDown事件處理程序。我測試了它,它工作正常。
我遇到了同樣的問題,發現禁用 RealTimeStylus(有效地禁用觸摸支持)對我有用,並導致滑鼠事件總是在觸摸時引發。
我們在 Windows 10 上使用支持多點觸控的工業觸摸屏。
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 }); } } } }