WPF 触控应用程序(部分)在 .NET Framework 4.7 上冻结
WPF touch application (partially) freezes on .NET Framework 4.7
更新
Microsoft acknowledged the issue:
Gepost door Microsoft op 13/10/2017 om 11:38
Thank you for reporting this.
We are aware of this issue and are fixing it in a future version of .NET.
There is also a related issue that is being released in a servicing fix that will drastically reduce the possibility of hitting this problem. This will be serviced relatively soon.
问题
我们的 WPF 应用程序正在使用触控(无手写笔)的平板电脑上使用,我们在安装 .NET Framework 4.7 后遇到问题。使用该应用程序一段时间后可能会发生两种情况:应用程序完全冻结并必须重新启动,或者 Popup
或 Window
元素中的所有触摸功能都被禁用。两者有很大的不同,但我相信原因是一样的。
场景一:完全冻结
- 应用程序完全没有响应,必须使用任务管理器关闭应用程序
- 可以使用触摸和鼠标
- 有时在应用程序挂起之前会抛出以下错误:
Index was outside the bounds of the array.
这是堆栈跟踪:
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Windows.Input.StylusWisp.WispLogic.CoalesceAndQueueStylusEvent(RawStylusInputReport inputReport)
at System.Windows.Input.StylusWisp.WispLogic.ProcessSystemEvent(PenContext penContext, Int32 tabletDeviceId, Int32 stylusDeviceId, Int32 timestamp, SystemGesture systemGesture, Int32 gestureX, Int32 gestureY, Int32 buttonState, PresentationSource inputSource)
at System.Windows.Input.PenContext.FireSystemGesture(Int32 stylusPointerId, Int32 timestamp)
at System.Windows.Input.PenThreadWorker.FireEvent(PenContext penContext, Int32 evt, Int32 stylusPointerId, Int32 cPackets, Int32 cbPacket, IntPtr pPackets)
at System.Windows.Input.PenThreadWorker.ThreadProc()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
场景二:部分冻结
- 主要 window 仍然响应(通过鼠标和触摸)但任何 'overlay' 内容(模态对话框,
Window
,Popup
来自 DatePicker
, ComboBox
, ...) 对点击没有反应。必须重新启动应用程序才能重新启用触摸。
- 鼠标仍然可以在 'overlay' 个元素中使用。
这个问题也有详细解释here。
可以找到问题发生后的行为视频 here。
附加信息
- 这两种情况都可以在不同类型的平板电脑上模拟,也可以在 Windows 模拟器上模拟,混合使用 Windows 8.1 和 Windows 10。
- 删除 .NET Framework 4.7 时问题已修复
- 场景 2 可以通过用多个手指快速点击一些
ComboBox
元素来轻松重现。几分钟后,弹出窗口不再响应触摸。
- 场景 1 更难模拟并且随机发生。
原因
问题似乎与 StylusWisp 代码有关。我猜它突然失败,在那之后变得无法使用。
当使用 DisableWPFTabletSupport or DisableStylusAndTouchSupport 禁用手写笔支持时,问题消失。但是,任何带有 PanningMode="Both"
的 ScrollViewer
都不能再滑动滚动了。
解决方案?
已向 Microsoft 报告 similar issue。由于还没有太多支持,修复可能需要一段时间。与此同时,我正在寻找解决此问题的方法,该解决方案不涉及禁用 .NET Framework 4.7 并且保持 原始触摸支持完好无损.有没有人有同样的问题和更好的解决方案?
更新:
以下解决方法的解决方法效果不佳。
问题是所有手指点击都被解释为鼠标点击。自定义触摸滚动仅适用于对鼠标点击没有反应的内容。为了使其正常工作,您需要找到一种方法来 "eat" 执行滚动操作时的鼠标单击事件。
我可能已经找到解决触摸滚动条损坏问题的解决方法。
处理 WM_TOUCH 并使用自定义 TouchDevice。
感谢 Luca Cornazzani:Enable multitouch on WPF controls
我使用的另一个来源(用于 TOUCHINPUT 定义):WPF and multi-touch
在应用程序启动时调用众所周知的 DisableWPFTabletSupport 函数。
MainWindow.xaml:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TouchScrollTest"
mc:Ignorable="d"
Title="MainWindow" Height="395.603" Width="525">
<Grid>
<StackPanel>
<ComboBox x:Name="comboBox1" FontSize="16" Width="150">
</ComboBox>
<ScrollViewer Height="300" Width="300" PanningMode="Both" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<TextBlock x:Name="textBlock1">
</TextBlock>
</ScrollViewer>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.vb:
Class MainWindow
Private _devices As New Dictionary(Of Integer, TouchDeviceEmulator)()
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
For i As Integer = 1 To 19
Dim myComboBoxItem As ComboBoxItem = New ComboBoxItem
myComboBoxItem.Content = "ComboBoxItem " & i.ToString()
comboBox1.Items.Add(myComboBoxItem)
Next
For i As Integer = 65 To 90
Dim c As Char = ChrW(i)
For j As Integer = 1 To 10
textBlock1.Text += " ".PadLeft(10, c)
Next
textBlock1.Text += vbCrLf
Next
End Sub
Protected Overrides Sub OnSourceInitialized(e As EventArgs)
MyBase.OnSourceInitialized(e)
Dim source As Interop.HwndSource = TryCast(PresentationSource.FromVisual(Me), Interop.HwndSource)
source.AddHook(New Interop.HwndSourceHook(AddressOf WndProc))
Dim presentation = DirectCast(PresentationSource.FromDependencyObject(Me), Interop.HwndSource)
If presentation Is Nothing Then
Throw New Exception("Unable to find the parent element host.")
End If
RegisterTouchWindow(presentation.Handle, TouchWindowFlag.WantPalm)
End Sub
Private Function WndProc(hwnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr, ByRef handled As Boolean) As IntPtr
' Handle messages...
If msg = WM_TOUCH Then
handled = HandleTouch(wParam, lParam)
Return New IntPtr(1)
End If
Return IntPtr.Zero
End Function
Private Function HandleTouch(wParam As IntPtr, lParam As IntPtr) As Boolean
Dim handled As Boolean = False
Dim inputCount = wParam.ToInt32() And &HFFFF
Dim inputs = New TOUCHINPUT(inputCount - 1) {}
If GetTouchInputInfo(lParam, inputCount, inputs, Runtime.InteropServices.Marshal.SizeOf(inputs(0))) Then
For i As Integer = 0 To inputCount - 1
Dim input As TOUCHINPUT = inputs(i)
'TOUCHINFO point coordinates and contact size is in 1/100 of a pixel; convert it to pixels.
'Also convert screen to client coordinates.
Dim position As Point = PointFromScreen(New System.Windows.Point((input.x * 0.01), (input.y * 0.01)))
Dim device As TouchDeviceEmulator = Nothing
If Not _devices.TryGetValue(input.dwID, device) Then
device = New TouchDeviceEmulator(input.dwID)
_devices.Add(input.dwID, device)
End If
device.Position = position
If (input.dwFlags And TOUCHEVENTF_DOWN) > 0 Then
device.SetActiveSource(PresentationSource.FromVisual(Me))
device.Activate()
device.ReportDown()
ElseIf device.IsActive AndAlso (input.dwFlags And TOUCHEVENTF_UP) > 0 Then
device.ReportUp()
device.Deactivate()
_devices.Remove(input.dwID)
ElseIf device.IsActive AndAlso (input.dwFlags And TOUCHEVENTF_MOVE) > 0 Then
device.ReportMove()
End If
Next
CloseTouchInputHandle(lParam)
handled = True
End If
Return handled
End Function
Private Class TouchDeviceEmulator
Inherits TouchDevice
Public Position As System.Windows.Point
Public Sub New(deviceId As Integer)
MyBase.New(deviceId)
End Sub
Public Overrides Function GetTouchPoint(relativeTo As IInputElement) As TouchPoint
Dim pt As System.Windows.Point = Position
If relativeTo IsNot Nothing Then
pt = ActiveSource.RootVisual.TransformToDescendant(DirectCast(relativeTo, Visual)).Transform(Position)
End If
Dim rect = New Rect(pt, New Size(1.0, 1.0))
Return New TouchPoint(Me, pt, rect, TouchAction.Move)
End Function
Public Overrides Function GetIntermediateTouchPoints(relativeTo As IInputElement) As TouchPointCollection
Throw New NotImplementedException()
End Function
Public Overloads Sub SetActiveSource(activeSource As PresentationSource)
MyBase.SetActiveSource(activeSource)
End Sub
Public Overloads Sub Activate()
MyBase.Activate()
End Sub
Public Overloads Sub ReportUp()
MyBase.ReportUp()
End Sub
Public Overloads Sub ReportDown()
MyBase.ReportDown()
End Sub
Public Overloads Sub ReportMove()
MyBase.ReportMove()
End Sub
Public Overloads Sub Deactivate()
MyBase.Deactivate()
End Sub
End Class
Private Const WM_TOUCH As Integer = &H240
Private Enum TouchWindowFlag As UInteger
FineTouch = &H1
WantPalm = &H2
End Enum
' Touch event flags ((TOUCHINPUT.dwFlags) [winuser.h]
Private Const TOUCHEVENTF_MOVE As Integer = &H1
Private Const TOUCHEVENTF_DOWN As Integer = &H2
Private Const TOUCHEVENTF_UP As Integer = &H4
Private Const TOUCHEVENTF_INRANGE As Integer = &H8
Private Const TOUCHEVENTF_PRIMARY As Integer = &H10
Private Const TOUCHEVENTF_NOCOALESCE As Integer = &H20
Private Const TOUCHEVENTF_PEN As Integer = &H40
Private Const TOUCHEVENTF_PALM As Integer = &H80
<Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Sequential)>
Private Structure TOUCHINPUT
Public x As Int32
Public y As Int32
Public hSource As IntPtr
Public dwID As Int32
Public dwFlags As Int32
Public dwMask As Int32
Public dwTime As Int32
Public dwExtraInfo As IntPtr
Public cxContact As Int32
Public cyContact As Int32
End Structure
<Runtime.InteropServices.DllImport("user32")>
Private Shared Function RegisterTouchWindow(hWnd As System.IntPtr, flags As TouchWindowFlag) As Boolean
End Function
<Runtime.InteropServices.DllImport("user32")>
Private Shared Function GetTouchInputInfo(hTouchInput As IntPtr, cInputs As Int32, <Runtime.InteropServices.[In], Runtime.InteropServices.Out> pInputs As TOUCHINPUT(), cbSize As Int32) As <Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.Bool)> [Boolean]
End Function
<Runtime.InteropServices.DllImport("user32")>
Private Shared Sub CloseTouchInputHandle(lParam As System.IntPtr)
End Sub
End Class
此示例中的大部分代码与 Cornazzani 的 C# 代码相同。
至少对于 ScrollViewer 它似乎有效,还没有测试其他控件。
它不能解决部分损坏的 Stylus 支持的问题。在 InkCanvas 上书写不像以前那样流畅,橡皮擦按钮在 DisableWPFTabletSupport hack 下根本不起作用。
同样有趣,相同的方法:github 上的 WmTouchDevice。
安装 .NET Framework 4.7.1 似乎解决了这个问题。 .NET Framework 4.7.1 也包含在自 10 月开始推出的 Windows 10 Fall Creators Update 中。
为什么它在 Windows10 创意者更新的 .NET Framework 4.7 中中断?
我的朋友lsj download the source code from https://referencesource.microsoft.com and find the .NET 4.7 for Windows 10 Creators Update没有给WispLogic.CoalesceAndQueueStylusEvent
加锁,另一个加了锁。
所以它只在 Windows10 Creators Update 的 .NET Framework 4.7 中中断。并且 .NET Framework 4.7 RTM 将锁添加到 WispLogic.CoalesceAndQueueStylusEvent
并修复它。
哪个版本加锁?
哪个版本解除锁定?
有趣的是 .NET 4.7 RTM 将锁添加到 WispLogic.CoalesceAndQueueStylusEvent
并 .NET 4.7.1 Downlevel 将其删除。
.NET 4.7.2 for Windows 10 April 2018 Creators Update 是第一个添加锁的版本,它似乎在 .NET 4.7.2 中修复,但在 .NET 4.7.1 中未修复
更新
Microsoft acknowledged the issue:
Gepost door Microsoft op 13/10/2017 om 11:38
Thank you for reporting this. We are aware of this issue and are fixing it in a future version of .NET. There is also a related issue that is being released in a servicing fix that will drastically reduce the possibility of hitting this problem. This will be serviced relatively soon.
问题
我们的 WPF 应用程序正在使用触控(无手写笔)的平板电脑上使用,我们在安装 .NET Framework 4.7 后遇到问题。使用该应用程序一段时间后可能会发生两种情况:应用程序完全冻结并必须重新启动,或者 Popup
或 Window
元素中的所有触摸功能都被禁用。两者有很大的不同,但我相信原因是一样的。
场景一:完全冻结
- 应用程序完全没有响应,必须使用任务管理器关闭应用程序
- 可以使用触摸和鼠标
- 有时在应用程序挂起之前会抛出以下错误:
Index was outside the bounds of the array.
这是堆栈跟踪:
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Windows.Input.StylusWisp.WispLogic.CoalesceAndQueueStylusEvent(RawStylusInputReport inputReport)
at System.Windows.Input.StylusWisp.WispLogic.ProcessSystemEvent(PenContext penContext, Int32 tabletDeviceId, Int32 stylusDeviceId, Int32 timestamp, SystemGesture systemGesture, Int32 gestureX, Int32 gestureY, Int32 buttonState, PresentationSource inputSource)
at System.Windows.Input.PenContext.FireSystemGesture(Int32 stylusPointerId, Int32 timestamp)
at System.Windows.Input.PenThreadWorker.FireEvent(PenContext penContext, Int32 evt, Int32 stylusPointerId, Int32 cPackets, Int32 cbPacket, IntPtr pPackets)
at System.Windows.Input.PenThreadWorker.ThreadProc()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
场景二:部分冻结
- 主要 window 仍然响应(通过鼠标和触摸)但任何 'overlay' 内容(模态对话框,
Window
,Popup
来自DatePicker
,ComboBox
, ...) 对点击没有反应。必须重新启动应用程序才能重新启用触摸。 - 鼠标仍然可以在 'overlay' 个元素中使用。
这个问题也有详细解释here。 可以找到问题发生后的行为视频 here。
附加信息
- 这两种情况都可以在不同类型的平板电脑上模拟,也可以在 Windows 模拟器上模拟,混合使用 Windows 8.1 和 Windows 10。
- 删除 .NET Framework 4.7 时问题已修复
- 场景 2 可以通过用多个手指快速点击一些
ComboBox
元素来轻松重现。几分钟后,弹出窗口不再响应触摸。 - 场景 1 更难模拟并且随机发生。
原因
问题似乎与 StylusWisp 代码有关。我猜它突然失败,在那之后变得无法使用。
当使用 DisableWPFTabletSupport or DisableStylusAndTouchSupport 禁用手写笔支持时,问题消失。但是,任何带有 PanningMode="Both"
的 ScrollViewer
都不能再滑动滚动了。
解决方案?
已向 Microsoft 报告 similar issue。由于还没有太多支持,修复可能需要一段时间。与此同时,我正在寻找解决此问题的方法,该解决方案不涉及禁用 .NET Framework 4.7 并且保持 原始触摸支持完好无损.有没有人有同样的问题和更好的解决方案?
更新:
以下解决方法的解决方法效果不佳。
问题是所有手指点击都被解释为鼠标点击。自定义触摸滚动仅适用于对鼠标点击没有反应的内容。为了使其正常工作,您需要找到一种方法来 "eat" 执行滚动操作时的鼠标单击事件。
我可能已经找到解决触摸滚动条损坏问题的解决方法。
处理 WM_TOUCH 并使用自定义 TouchDevice。
感谢 Luca Cornazzani:Enable multitouch on WPF controls
我使用的另一个来源(用于 TOUCHINPUT 定义):WPF and multi-touch
在应用程序启动时调用众所周知的 DisableWPFTabletSupport 函数。
MainWindow.xaml:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TouchScrollTest"
mc:Ignorable="d"
Title="MainWindow" Height="395.603" Width="525">
<Grid>
<StackPanel>
<ComboBox x:Name="comboBox1" FontSize="16" Width="150">
</ComboBox>
<ScrollViewer Height="300" Width="300" PanningMode="Both" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<TextBlock x:Name="textBlock1">
</TextBlock>
</ScrollViewer>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.vb:
Class MainWindow
Private _devices As New Dictionary(Of Integer, TouchDeviceEmulator)()
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
For i As Integer = 1 To 19
Dim myComboBoxItem As ComboBoxItem = New ComboBoxItem
myComboBoxItem.Content = "ComboBoxItem " & i.ToString()
comboBox1.Items.Add(myComboBoxItem)
Next
For i As Integer = 65 To 90
Dim c As Char = ChrW(i)
For j As Integer = 1 To 10
textBlock1.Text += " ".PadLeft(10, c)
Next
textBlock1.Text += vbCrLf
Next
End Sub
Protected Overrides Sub OnSourceInitialized(e As EventArgs)
MyBase.OnSourceInitialized(e)
Dim source As Interop.HwndSource = TryCast(PresentationSource.FromVisual(Me), Interop.HwndSource)
source.AddHook(New Interop.HwndSourceHook(AddressOf WndProc))
Dim presentation = DirectCast(PresentationSource.FromDependencyObject(Me), Interop.HwndSource)
If presentation Is Nothing Then
Throw New Exception("Unable to find the parent element host.")
End If
RegisterTouchWindow(presentation.Handle, TouchWindowFlag.WantPalm)
End Sub
Private Function WndProc(hwnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr, ByRef handled As Boolean) As IntPtr
' Handle messages...
If msg = WM_TOUCH Then
handled = HandleTouch(wParam, lParam)
Return New IntPtr(1)
End If
Return IntPtr.Zero
End Function
Private Function HandleTouch(wParam As IntPtr, lParam As IntPtr) As Boolean
Dim handled As Boolean = False
Dim inputCount = wParam.ToInt32() And &HFFFF
Dim inputs = New TOUCHINPUT(inputCount - 1) {}
If GetTouchInputInfo(lParam, inputCount, inputs, Runtime.InteropServices.Marshal.SizeOf(inputs(0))) Then
For i As Integer = 0 To inputCount - 1
Dim input As TOUCHINPUT = inputs(i)
'TOUCHINFO point coordinates and contact size is in 1/100 of a pixel; convert it to pixels.
'Also convert screen to client coordinates.
Dim position As Point = PointFromScreen(New System.Windows.Point((input.x * 0.01), (input.y * 0.01)))
Dim device As TouchDeviceEmulator = Nothing
If Not _devices.TryGetValue(input.dwID, device) Then
device = New TouchDeviceEmulator(input.dwID)
_devices.Add(input.dwID, device)
End If
device.Position = position
If (input.dwFlags And TOUCHEVENTF_DOWN) > 0 Then
device.SetActiveSource(PresentationSource.FromVisual(Me))
device.Activate()
device.ReportDown()
ElseIf device.IsActive AndAlso (input.dwFlags And TOUCHEVENTF_UP) > 0 Then
device.ReportUp()
device.Deactivate()
_devices.Remove(input.dwID)
ElseIf device.IsActive AndAlso (input.dwFlags And TOUCHEVENTF_MOVE) > 0 Then
device.ReportMove()
End If
Next
CloseTouchInputHandle(lParam)
handled = True
End If
Return handled
End Function
Private Class TouchDeviceEmulator
Inherits TouchDevice
Public Position As System.Windows.Point
Public Sub New(deviceId As Integer)
MyBase.New(deviceId)
End Sub
Public Overrides Function GetTouchPoint(relativeTo As IInputElement) As TouchPoint
Dim pt As System.Windows.Point = Position
If relativeTo IsNot Nothing Then
pt = ActiveSource.RootVisual.TransformToDescendant(DirectCast(relativeTo, Visual)).Transform(Position)
End If
Dim rect = New Rect(pt, New Size(1.0, 1.0))
Return New TouchPoint(Me, pt, rect, TouchAction.Move)
End Function
Public Overrides Function GetIntermediateTouchPoints(relativeTo As IInputElement) As TouchPointCollection
Throw New NotImplementedException()
End Function
Public Overloads Sub SetActiveSource(activeSource As PresentationSource)
MyBase.SetActiveSource(activeSource)
End Sub
Public Overloads Sub Activate()
MyBase.Activate()
End Sub
Public Overloads Sub ReportUp()
MyBase.ReportUp()
End Sub
Public Overloads Sub ReportDown()
MyBase.ReportDown()
End Sub
Public Overloads Sub ReportMove()
MyBase.ReportMove()
End Sub
Public Overloads Sub Deactivate()
MyBase.Deactivate()
End Sub
End Class
Private Const WM_TOUCH As Integer = &H240
Private Enum TouchWindowFlag As UInteger
FineTouch = &H1
WantPalm = &H2
End Enum
' Touch event flags ((TOUCHINPUT.dwFlags) [winuser.h]
Private Const TOUCHEVENTF_MOVE As Integer = &H1
Private Const TOUCHEVENTF_DOWN As Integer = &H2
Private Const TOUCHEVENTF_UP As Integer = &H4
Private Const TOUCHEVENTF_INRANGE As Integer = &H8
Private Const TOUCHEVENTF_PRIMARY As Integer = &H10
Private Const TOUCHEVENTF_NOCOALESCE As Integer = &H20
Private Const TOUCHEVENTF_PEN As Integer = &H40
Private Const TOUCHEVENTF_PALM As Integer = &H80
<Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Sequential)>
Private Structure TOUCHINPUT
Public x As Int32
Public y As Int32
Public hSource As IntPtr
Public dwID As Int32
Public dwFlags As Int32
Public dwMask As Int32
Public dwTime As Int32
Public dwExtraInfo As IntPtr
Public cxContact As Int32
Public cyContact As Int32
End Structure
<Runtime.InteropServices.DllImport("user32")>
Private Shared Function RegisterTouchWindow(hWnd As System.IntPtr, flags As TouchWindowFlag) As Boolean
End Function
<Runtime.InteropServices.DllImport("user32")>
Private Shared Function GetTouchInputInfo(hTouchInput As IntPtr, cInputs As Int32, <Runtime.InteropServices.[In], Runtime.InteropServices.Out> pInputs As TOUCHINPUT(), cbSize As Int32) As <Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.Bool)> [Boolean]
End Function
<Runtime.InteropServices.DllImport("user32")>
Private Shared Sub CloseTouchInputHandle(lParam As System.IntPtr)
End Sub
End Class
此示例中的大部分代码与 Cornazzani 的 C# 代码相同。
至少对于 ScrollViewer 它似乎有效,还没有测试其他控件。
它不能解决部分损坏的 Stylus 支持的问题。在 InkCanvas 上书写不像以前那样流畅,橡皮擦按钮在 DisableWPFTabletSupport hack 下根本不起作用。
同样有趣,相同的方法:github 上的 WmTouchDevice。
安装 .NET Framework 4.7.1 似乎解决了这个问题。 .NET Framework 4.7.1 也包含在自 10 月开始推出的 Windows 10 Fall Creators Update 中。
为什么它在 Windows10 创意者更新的 .NET Framework 4.7 中中断?
我的朋友lsj download the source code from https://referencesource.microsoft.com and find the .NET 4.7 for Windows 10 Creators Update没有给WispLogic.CoalesceAndQueueStylusEvent
加锁,另一个加了锁。
所以它只在 Windows10 Creators Update 的 .NET Framework 4.7 中中断。并且 .NET Framework 4.7 RTM 将锁添加到 WispLogic.CoalesceAndQueueStylusEvent
并修复它。
哪个版本加锁?
哪个版本解除锁定?
有趣的是 .NET 4.7 RTM 将锁添加到 WispLogic.CoalesceAndQueueStylusEvent
并 .NET 4.7.1 Downlevel 将其删除。
.NET 4.7.2 for Windows 10 April 2018 Creators Update 是第一个添加锁的版本,它似乎在 .NET 4.7.2 中修复,但在 .NET 4.7.1 中未修复