演练 - 创建您的第一个触摸应用

WPF 使应用程序能够响应触摸。 例如,可以在触摸敏感设备上使用一个或多个手指与应用程序交互,例如触摸屏。本演练创建一个应用程序,使用户能够使用触摸移动、调整大小或旋转单个对象。

先决条件

需要以下组件才能完成本演练:

  • Visual Studio。

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

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

创建应用程序

创建应用程序

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

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

    此标记创建一个简单的应用程序,其中包含红色的 RectangleCanvasRectangleIsManipulationEnabled 属性设置为 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 事件处理程序。

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

    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 将继续移动、调整大小或旋转几秒钟。

另请参阅