演练:创建您的第一个触控应用程序

WPF 使应用程序能够响应触控。 例如,可以通过在触控敏感型设备(如触摸屏)上使用一根或多根手指与应用程序交互。本演练创建了一个应用程序,使用户能够使用触控来移动、旋转单个对象或重设其大小。

先决条件

你需要满足以下条件才能完成本演练:

  • Visual Studio。

  • 一种接受触控输入的设备,例如支持 Windows Touch 的触摸屏。

此外,应对如何在 WPF 中创建应用程序,尤其是如何订阅和处理事件有一个基本的了解。 有关详细信息,请参阅演练:我的第一个 WPF 桌面应用程序

创建应用程序

创建应用程序

  1. 使用 Visual Basic 或 Visual C# 创建名为 BasicManipulation 的新 WPF 应用程序项目。 有关详细信息,请参阅演练:我的第一个 WPF 桌面应用程序

  2. 将 MainWindow.xaml 的内容替换为以下 XAML。

    此标记创建一个简单的应用程序,该应用程序在 Canvas 上包含一个红色 RectangleRectangleIsManipulationEnabled 属性设置为 true,以便接收操作事件。 应用程序订阅 ManipulationStartingManipulationDeltaManipulationInertiaStarting 事件。 这些事件包含用于在用户操作 Rectangle 时移动它的逻辑。

    <Window x:Class="BasicManipulation.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Move, Size, and Rotate the Square"
            WindowState="Maximized"
            ManipulationStarting="Window_ManipulationStarting"
            ManipulationDelta="Window_ManipulationDelta"
            ManipulationInertiaStarting="Window_InertiaStarting">
      <Window.Resources>
    
        <!--The movement, rotation, and size of the Rectangle is 
            specified by its RenderTransform.-->
        <MatrixTransform x:Key="InitialMatrixTransform">
          <MatrixTransform.Matrix>
            <Matrix OffsetX="200" OffsetY="200"/>
          </MatrixTransform.Matrix>
        </MatrixTransform>
    
      </Window.Resources>
    
      <Canvas>
        <Rectangle Fill="Red" Name="manRect"
                     Width="200" Height="200" 
                     RenderTransform="{StaticResource InitialMatrixTransform}"
                     IsManipulationEnabled="true" />
      </Canvas>
    </Window>
    
    
  3. 如果使用的是 Visual Basic,则在 MainWindow.xaml 的第一行中,将 x:Class="BasicManipulation.MainWindow" 替换为 x:Class="MainWindow"

  4. MainWindow 类中,添加以下 ManipulationStarting 事件处理程序。

    当 WPF 检测到触控输入开始操作对象时,将发生 ManipulationStarting 事件。 代码通过设置 ManipulationContainer 属性来指定操作的位置应相对于 Window

    void Window_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
    {
        e.ManipulationContainer = this;
        e.Handled = true;
    }
    
    Private Sub Window_ManipulationStarting(ByVal sender As Object, ByVal e As ManipulationStartingEventArgs)
        e.ManipulationContainer = Me
        e.Handled = True
    End Sub
    
  5. MainWindow 类中,添加以下 ManipulationDelta 事件处理程序。

    当触控输入改变位置时,会发生 ManipulationDelta 事件,该事件可在操作期间多次发生。 该事件也可以在手指抬起后发生。 例如,如果用户在屏幕上拖动手指,则 ManipulationDelta 事件会在手指移动时发生多次。 当用户从屏幕上抬起手指时,ManipulationDelta 事件会不断发生以模拟惯性。

    该代码将 DeltaManipulation 应用于 RectangleRenderTransform 以在用户移动触控输入时移动它。 它还会检查当事件在惯性期间发生时,Rectangle 是否超出了 Window 的边界。 如果是,应用程序会调用 ManipulationDeltaEventArgs.Complete 方法来结束操作。

    void Window_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
    {
    
        // Get the Rectangle and its RenderTransform matrix.
        Rectangle rectToMove = e.OriginalSource as Rectangle;
        Matrix rectsMatrix = ((MatrixTransform)rectToMove.RenderTransform).Matrix;
    
        // Rotate the Rectangle.
        rectsMatrix.RotateAt(e.DeltaManipulation.Rotation,
                             e.ManipulationOrigin.X,
                             e.ManipulationOrigin.Y);
    
        // Resize the Rectangle.  Keep it square
        // so use only the X value of Scale.
        rectsMatrix.ScaleAt(e.DeltaManipulation.Scale.X,
                            e.DeltaManipulation.Scale.X,
                            e.ManipulationOrigin.X,
                            e.ManipulationOrigin.Y);
    
        // Move the Rectangle.
        rectsMatrix.Translate(e.DeltaManipulation.Translation.X,
                              e.DeltaManipulation.Translation.Y);
    
        // Apply the changes to the Rectangle.
        rectToMove.RenderTransform = new MatrixTransform(rectsMatrix);
    
        Rect containingRect =
            new Rect(((FrameworkElement)e.ManipulationContainer).RenderSize);
    
        Rect shapeBounds =
            rectToMove.RenderTransform.TransformBounds(
                new Rect(rectToMove.RenderSize));
    
        // Check if the rectangle is completely in the window.
        // If it is not and intertia is occuring, stop the manipulation.
        if (e.IsInertial && !containingRect.Contains(shapeBounds))
        {
            e.Complete();
        }
    
        e.Handled = true;
    }
    
    Private Sub Window_ManipulationDelta(ByVal sender As Object, ByVal e As ManipulationDeltaEventArgs)
    
        ' Get the Rectangle and its RenderTransform matrix.
        Dim rectToMove As Rectangle = e.OriginalSource
        Dim rectTransform As MatrixTransform = rectToMove.RenderTransform
        Dim rectsMatrix As Matrix = rectTransform.Matrix
    
    
        ' Rotate the shape
        rectsMatrix.RotateAt(e.DeltaManipulation.Rotation,
                             e.ManipulationOrigin.X,
                             e.ManipulationOrigin.Y)
    
        ' Resize the Rectangle. Keep it square 
        ' so use only the X value of Scale.
        rectsMatrix.ScaleAt(e.DeltaManipulation.Scale.X,
                            e.DeltaManipulation.Scale.X,
                            e.ManipulationOrigin.X,
                            e.ManipulationOrigin.Y)
    
        'move the center
        rectsMatrix.Translate(e.DeltaManipulation.Translation.X,
                              e.DeltaManipulation.Translation.Y)
    
        ' Apply the changes to the Rectangle.
        rectTransform = New MatrixTransform(rectsMatrix)
        rectToMove.RenderTransform = rectTransform
    
        Dim container As FrameworkElement = e.ManipulationContainer
        Dim containingRect As New Rect(container.RenderSize)
    
        Dim shapeBounds As Rect = rectTransform.TransformBounds(
                                    New Rect(rectToMove.RenderSize))
    
        ' Check if the rectangle is completely in the window.
        ' If it is not and intertia is occuring, stop the manipulation.
        If e.IsInertial AndAlso Not containingRect.Contains(shapeBounds) Then
            e.Complete()
        End If
    
        e.Handled = True
    End Sub
    
  6. MainWindow 类中,添加以下 ManipulationInertiaStarting 事件处理程序。

    当用户从屏幕上抬起所有手指时,会发生 ManipulationInertiaStarting 事件。 代码设置矩形移动、扩展和旋转的初始速度和减速度。

    void Window_InertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
    {
    
        // Decrease the velocity of the Rectangle's movement by
        // 10 inches per second every second.
        // (10 inches * 96 pixels per inch / 1000ms^2)
        e.TranslationBehavior.DesiredDeceleration = 10.0 * 96.0 / (1000.0 * 1000.0);
    
        // Decrease the velocity of the Rectangle's resizing by
        // 0.1 inches per second every second.
        // (0.1 inches * 96 pixels per inch / (1000ms^2)
        e.ExpansionBehavior.DesiredDeceleration = 0.1 * 96 / (1000.0 * 1000.0);
    
        // Decrease the velocity of the Rectangle's rotation rate by
        // 2 rotations per second every second.
        // (2 * 360 degrees / (1000ms^2)
        e.RotationBehavior.DesiredDeceleration = 720 / (1000.0 * 1000.0);
    
        e.Handled = true;
    }
    
    Private Sub Window_InertiaStarting(ByVal sender As Object,
                                       ByVal e As ManipulationInertiaStartingEventArgs)
    
        ' Decrease the velocity of the Rectangle's movement by 
        ' 10 inches per second every second.
        ' (10 inches * 96 pixels per inch / 1000ms^2)
        e.TranslationBehavior.DesiredDeceleration = 10.0 * 96.0 / (1000.0 * 1000.0)
    
        ' Decrease the velocity of the Rectangle's resizing by 
        ' 0.1 inches per second every second.
        ' (0.1 inches * 96 pixels per inch / (1000ms^2)
        e.ExpansionBehavior.DesiredDeceleration = 0.1 * 96 / (1000.0 * 1000.0)
    
        ' Decrease the velocity of the Rectangle's rotation rate by 
        ' 2 rotations per second every second.
        ' (2 * 360 degrees / (1000ms^2)
        e.RotationBehavior.DesiredDeceleration = 720 / (1000.0 * 1000.0)
    
        e.Handled = True
    End Sub
    
  7. 生成并运行该项目。

    应会在窗口中看到一个红色方块。

测试应用程序

若要测试应用程序,请尝试以下操作。 请注意,可以同时执行以下多项操作。

  • 若要移动 Rectangle,请将手指放在 Rectangle 上,然后在屏幕上移动手指。

  • 若要重设 Rectangle 的大小,请将两根手指放在 Rectangle 上,然后将手指相互靠拢或分开。

  • 若要旋转 Rectangle,请将两根手指放在 Rectangle 上并同向转动手指。

若要引起惯性,请在执行之前的操作时将手指从屏幕上快速抬起。 Rectangle 将继续移动、重设大小或旋转几秒钟,然后才停止。

另请参阅