Walkthrough: Creating Your First Touch Application

WPF enables applications to respond to touch. For example, you can interact with an application by using one or more fingers on a touch-sensitive device, such as a touchscreen This walkthrough creates an application that enables the user to move, resize, or rotate a single object by using touch.

Prerequisites

You need the following components to complete this walkthrough:

• Visual Studio.

• A device that accepts touch input, such as a touchscreen, that supports Windows Touch.

Additionally, you should have a basic understanding of how to create an application in WPF, especially how to subscribe to and handle an event. For more information, see Walkthrough: My first WPF desktop application.

Creating the Application

To create the application

1. Create a new WPF Application project in Visual Basic or Visual C# named BasicManipulation. For more information, see Walkthrough: My first WPF desktop application.

2. Replace the contents of MainWindow.xaml with the following XAML.

This markup creates a simple application that contains a red Rectangle on a Canvas. The IsManipulationEnabled property of the Rectangle is set to true so that it will receive manipulation events. The application subscribes to the ManipulationStarting, ManipulationDelta, and ManipulationInertiaStarting events. These events contain the logic to move the Rectangle when the user manipulates it.

<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. If you are using Visual Basic, in the first line of MainWindow.xaml, replace x:Class="BasicManipulation.MainWindow" with x:Class="MainWindow".

4. In the MainWindow class, add the following ManipulationStarting event handler.

The ManipulationStarting event occurs when WPF detects that touch input begins to manipulate an object. The code specifies that the position of the manipulation should be relative to the Window by setting the ManipulationContainer property.

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. In the MainWindow class, add the following ManipulationDelta event handler.

The ManipulationDelta event occurs when the touch input changes position and can occur multiple times during a manipulation. The event can also occur after a finger is raised. For example, if the user drags a finger across a screen, the ManipulationDelta event occurs multiple times as the finger moves. When the user raises a finger from the screen, the ManipulationDelta event keeps occurring to simulate inertia.

The code applies the DeltaManipulation to the RenderTransform of the Rectangle to move it as the user moves the touch input. It also checks whether the Rectangle is outside the bounds of the Window when the event occurs during inertia. If so, the application calls the ManipulationDeltaEventArgs.Complete method to end the manipulation.

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. In the MainWindow class, add the following ManipulationInertiaStarting event handler.

The ManipulationInertiaStarting event occurs when the user raises all fingers from the screen. The code sets the initial velocity and deceleration for the movement, expansion, and rotation of the rectangle.

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. Build and run the project.

You should see a red square appear in the window.

Testing the Application

To test the application, try the following manipulations. Note that you can do more than one of the following at the same time.

• To move the Rectangle, put a finger on the Rectangle and move the finger across the screen.

• To resize the Rectangle, put two fingers on the Rectangle and move the fingers closer together or farther apart from each other.

• To rotate the Rectangle, put two fingers on the Rectangle and rotate the fingers around each other.

To cause inertia, quickly raise your fingers from the screen as you perform the previous manipulations. The Rectangle will continue to move, resize, or rotate for a few seconds before it stops.