演练:创建您的第一个触控应用程序
WPF 使应用程序能够响应触控。 例如,可以通过在触控敏感型设备(如触摸屏)上使用一根或多根手指与应用程序交互。本演练创建了一个应用程序,使用户能够使用触控来移动、旋转单个对象或重设其大小。
先决条件
你需要满足以下条件才能完成本演练:
Visual Studio。
一种接受触控输入的设备,例如支持 Windows Touch 的触摸屏。
此外,应对如何在 WPF 中创建应用程序,尤其是如何订阅和处理事件有一个基本的了解。 有关详细信息,请参阅演练:我的第一个 WPF 桌面应用程序。
创建应用程序
创建应用程序
使用 Visual Basic 或 Visual C# 创建名为
BasicManipulation
的新 WPF 应用程序项目。 有关详细信息,请参阅演练:我的第一个 WPF 桌面应用程序。将 MainWindow.xaml 的内容替换为以下 XAML。
此标记创建一个简单的应用程序,该应用程序在 Canvas 上包含一个红色 Rectangle。 Rectangle 的 IsManipulationEnabled 属性设置为 true,以便接收操作事件。 应用程序订阅 ManipulationStarting、ManipulationDelta 和 ManipulationInertiaStarting 事件。 这些事件包含用于在用户操作 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>
如果使用的是 Visual Basic,则在 MainWindow.xaml 的第一行中,将
x:Class="BasicManipulation.MainWindow"
替换为x:Class="MainWindow"
。在
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
在
MainWindow
类中,添加以下 ManipulationDelta 事件处理程序。当触控输入改变位置时,会发生 ManipulationDelta 事件,该事件可在操作期间多次发生。 该事件也可以在手指抬起后发生。 例如,如果用户在屏幕上拖动手指,则 ManipulationDelta 事件会在手指移动时发生多次。 当用户从屏幕上抬起手指时,ManipulationDelta 事件会不断发生以模拟惯性。
该代码将 DeltaManipulation 应用于 Rectangle 的 RenderTransform 以在用户移动触控输入时移动它。 它还会检查当事件在惯性期间发生时,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
在
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
生成并运行该项目。
应会在窗口中看到一个红色方块。
测试应用程序
若要测试应用程序,请尝试以下操作。 请注意,可以同时执行以下多项操作。
若要引起惯性,请在执行之前的操作时将手指从屏幕上快速抬起。 Rectangle 将继续移动、重设大小或旋转几秒钟,然后才停止。