9

我有一个面向 .NET Framework 4 的现有 Windows 窗体桌面应用程序,并希望向其添加 Windows 8 触摸支持。

目前该程序在 Windows 8 中运行良好,我可以调整一些元素的大小,使其在触摸设备上更加用户友好。但是,在数据网格上添加手势(例如捏合缩放)以及对其他元素的滑动支持将大大有助于使应用程序在纯触摸环境中更加现代。

我正在投资 Visual Studio 2012,它可以让我瞄准 .NET 4.5 和新的 Windows 8 功能,但是有人知道任何可以帮助我更新应用程序的资源吗?我特别关心以下几点:

  • 无法在我的非触控开发机器上直接测试应用程序的触控功能。微软的模拟器似乎只支持 Metro 应用程序。我听说诸如 Splashtop 之类的平板电脑应用程序可以提供帮助(我有一个 Android 平板电脑),但还没有看到任何具体的具体情况
  • WinForms 应用程序是否支持手势。我是否必须将整个 UI 升级到 WPF 才能使其正常工作?(如果我真的走这条路,我相信我也可以针对 Windows 7,因为 WPF 4 支持多点触控)
  • 在运行时检测设备的触控支持并适当地缩放/更改 UI,类似于 Microsoft 的 Windows RT Office 应用程序上的触控模式设置。我不想为了添加新功能而分叉项目
  • 触摸交互的自动化测试

无论如何,这并不是一份详尽的清单,但我非常感谢那些过去可能进行过类似升级的人的任何建议。

4

5 回答 5

6

在运行时检测设备的触摸支持是有问题的,因为用户可以随时连接触摸设备。如果您在检测到触摸设备连接后调整表单大小并且设备的连接不稳定,您最终可能会得到一个不断调整自身大小的表单。最好为所有输入提供一个稳定的界面(例如,使用功能区而不是小菜单栏)。如果你真的想检测触摸设备,你可以用 SM_DIGITIZER 调用 GetSystemMetrics。

Windows 窗体不支持手势(2005 年冻结的功能)。然而,表单控件仍然可以使用触摸输入,因为默认的触摸处理程序会将触摸转换为鼠标点击。如果您想拥有自己的触摸处理程序,因为触摸输入以 Windows 消息的形式发送,您可以覆盖您的表单或控件的WndProc函数来处理手势消息。有关示例代码,请查看Windows 7 SDK 中的Windows Touch Samples

要为您的触摸功能编写测试代码,您可以调用 InjectTouchInput 来模拟触摸输入。完整的示例可以在Input: Touch injection sample中找到。

于 2014-07-31T22:47:50.780 回答
6

您可以从组件一中使用TouchToolkit for WinForms 。但是我认为您必须重写您的应用程序才能使用这些组件。

在此处输入图像描述

于 2014-07-28T00:48:30.740 回答
5

关于“无法在我的非触摸开发机器上直接测试应用程序的触摸功能。微软的模拟器似乎只支持 Metro 应用程序”的评论- 我能够运行模拟器,进入模拟器中的桌面并运行模拟触摸输入时的任何应用程序 - 包括 WinForms 应用程序。

由于 WinForms 只是 WinAPI 的本机 UI API 的包装器 - 您可以使用 p/Invoke 来使用我认为是在 Vista/Windows 7 时间范围内添加的触摸 API。主要是WM_TOUCHWM_GESTURE消息。有很多关于 p/Invoking 和 using 的示例,protected override void WndProc(ref Message m)它们是您处理触摸所需的主要内容。除此之外 - 默认情况下,触摸输入在不作为触摸处理时会自动提升为鼠标事件,因此很多事情都可以正常工作。

于 2014-08-01T16:41:20.080 回答
2

触摸应该或多或少“正常工作”,但当然,按钮需要更大等。另请参阅此处了解比触摸更复杂的手势。

于 2012-11-10T02:02:57.153 回答
1

向 winforms 添加手势支持 - 在这里解决:

http://portal.fke.utm.my/libraryfke/files/1387_LIEWHONCHIN2011.pdf

'Imports System.Security.Permissions
'Imports System.Runtime.InteropServices


  Private first_point As New Point()
  Private second_point As New Point()
  Private iArguments As Integer = 0
  Private Const ULL_ARGUMENTS_BIT_MASK As Int64 = &HFFFFFFFFL
  Private Const WM_GESTURENOTIFY As Integer = &H11A
  Private Const WM_GESTURE As Integer = &H119
  Private Const GC_ALLGESTURES As Integer = &H1
  Private Const GID_BEGIN As Integer = 1
  Private Const GID_END As Integer = 2
  Private Const GID_ZOOM As Integer = 3
  Private Const GID_PAN As Integer = 4
  Private Const GID_ROTATE As Integer = 5
  Private Const GID_TWOFINGERTAP As Integer = 6
  Private Const GID_PRESSANDTAP As Integer = 7
  Private Const GF_BEGIN As Integer = &H1
  Private Const GF_INERTIA As Integer = &H2
  Private Const GF_END As Integer = &H4
  Private Structure GESTURECONFIG
    Public dwID As Integer
    Public dwWant As Integer
    Public dwBlock As Integer
  End Structure
  Private Structure POINTS
    Public x As Short
    Public y As Short
  End Structure
  Private Structure GESTUREINFO
    Public cbSize As Integer
    Public dwFlags As Integer
    Public dwID As Integer
    Public hwndTarget As IntPtr
    <MarshalAs(UnmanagedType.Struct)>
    Friend ptsLocation As POINTS
    Public dwInstanceID As Integer
    Public dwSequenceID As Integer
    Public ullArguments As Int64
    Public cbExtraArgs As Integer
  End Structure
  <DllImport("user32")> _
  Private Shared Function SetGestureConfig(ByVal hWnd As IntPtr, ByVal dwReserved As Integer, ByVal cIDs As Integer, ByRef pGestureConfig As GESTURECONFIG, ByVal cbSize As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
  End Function
  <DllImport("user32")>
  Private Shared Function GetGestureInfo(ByVal hGestureInfo As IntPtr, ByRef pGestureInfo As GESTUREINFO) As <MarshalAs(UnmanagedType.Bool)> Boolean
  End Function
  Private _gestureConfigSize As Integer
  Private _gestureInfoSize As Integer
  <SecurityPermission(SecurityAction.Demand)>
  Private Sub SetupStructSizes()
    _gestureConfigSize = Marshal.SizeOf(New GESTURECONFIG())
    _gestureInfoSize = Marshal.SizeOf(New GESTUREINFO())
  End Sub
  <PermissionSet(SecurityAction.Demand, Name:="FullTrust")>
  Protected Overrides Sub WndProc(ByRef m As Message)
    Dim handled As Boolean
    Select Case m.Msg
      Case WM_GESTURENOTIFY
        Dim gc As New GESTURECONFIG()
        gc.dwID = 0
        gc.dwWant = GC_ALLGESTURES
        gc.dwBlock = 0
        Dim bResult As Boolean = SetGestureConfig(Handle, 0, 1, gc, _gestureConfigSize)
        If Not bResult Then
          Throw New Exception("Error in execution of SetGestureConfig")
        End If
        handled = True
      Case WM_GESTURE
        handled = DecodeGesture(m)
      Case Else
        handled = False
    End Select
    MyBase.WndProc(m)
    If handled Then
      Try
        m.Result = New IntPtr(1)
      Catch excep As Exception
        Debug.Print("Could not allocate result ptr")
        Debug.Print(excep.ToString())
      End Try
    End If
  End Sub
  Private Function DecodeGesture(ByRef m As Message) As Boolean
    Dim gi As GESTUREINFO
    Try
      gi = New GESTUREINFO()
    Catch excep As Exception
      Debug.Print("Could not allocate resources to decode gesture")
      Debug.Print(excep.ToString())
      Return False
    End Try
    gi.cbSize = _gestureInfoSize
    If Not GetGestureInfo(m.LParam, gi) Then
      Return False
    End If
    Select Case gi.dwID
      Case GID_BEGIN, GID_END
      Case GID_TWOFINGERTAP
        'Receipt.Show()
        'Invalidate()
      Case GID_ZOOM
        Select Case gi.dwFlags
          Case GF_BEGIN
            iArguments = CInt(Fix(gi.ullArguments And
            ULL_ARGUMENTS_BIT_MASK))
            first_point.X = gi.ptsLocation.x
            first_point.Y = gi.ptsLocation.y
            first_point = PointToClient(first_point)
          Case Else
            second_point.X = gi.ptsLocation.x
            second_point.Y = gi.ptsLocation.y
            second_point = PointToClient(second_point)
            RaiseEvent GestureHappened(Me, New GestureEventArgs With {.Operation = Gestures.Pan, .FirstPoint = first_point, .SecondPoint = second_point})
            'Invalidate()
            'MsgBox("zoom")
        End Select
      Case GID_PAN
        Select Case gi.dwFlags
          Case GF_BEGIN
            first_point.X = gi.ptsLocation.x
            first_point.Y = gi.ptsLocation.y
            first_point = PointToClient(first_point)
          Case Else
            second_point.X = gi.ptsLocation.x
            second_point.Y = gi.ptsLocation.y
            second_point = PointToClient(second_point)
            RaiseEvent GestureHappened(Me, New GestureEventArgs With {.Operation = Gestures.Pan, .FirstPoint = first_point, .SecondPoint = second_point})
            'Invalidate()
            'MsgBox("pan")
        End Select
      Case GID_PRESSANDTAP
        'If gi.dwFlags = GF_BEGIN Then
        '  Invalidate()
        'End If
      Case GID_ROTATE
        'Select Case gi.dwFlags
        '  Case GF_BEGIN
        '    iArguments = 0
        '  Case Else
        '    first_point.X = gi.ptsLocation.x
        '    first_point.Y = gi.ptsLocation.y
        '    first_point = PointToClient(first_point)
        '    Invalidate()
        'End Select
    End Select
    Return True
  End Function


  Public Enum Gestures
    Pan
    Zoom
  End Enum

  Public Class GestureEventArgs
    Inherits EventArgs
    Public Property Operation As Gestures
    Public Property FirstPoint As Point
    Public Property SecondPoint As Point
  End Class

  Public Event GestureHappened(sender As Object, e As GestureEventArgs)
于 2016-01-27T22:54:10.910 回答