Touch and Gestures

0
176

In most cases, your application will use events exposed by the UI controls to detect user input, such as the Click event of a Button
control or the TextChanged event of a TextBox control. However, you can capture user touch and gestures directly if you want. This may
be useful for gestures such as drag, flick, and hold. Windows Phone 7 provides native support for gesture detection using both Silverlight
and XNA.

The TouchPanel class in the XNA Framework libraries is designed to provide advanced gesture detection capabilities for games and
other XNA-based interactive applications. You can use the XNA interop capabilities of Silverlight to implement gesture detection using
this approach if you want.

However, for a Silverlight application, you can take advantage of two other simpler approaches to gesture detection. You can use the
built-in manipulation mechanism for Silverlight controls, or you can install and use the GestureListener control that is included in the
Silverlight for Windows Phone Toolkit.

The following table provides a comparison of the approaches you can use.

provides a comparison of the approaches

Gesture Detection using Silverlight Manipulation Events

The Windows Phone page and most of the UI controls automatically support manipulation events. You can detect manipulation at the individual control level, or for the page as a whole, by handling the three events that occur when manipulation of the control or page starts,
each time a movement (a delta) is detected, and when the manipulation ends.

The following code example shows how you can wire up handlers for the three manipulation events of the page.

C#
public MainPage()
{
InitializeComponent();
this.ManipulationStarted +=
this.PhoneApplicationPage_ManipulationStarted;
this.ManipulationDelta +=
this.PhoneApplicationPage_ManipulationDelta;
this.ManipulationCompleted +=
this.PhoneApplicationPage_ManipulationCompleted;
}

Each of these events passes a specific type of argument class to the handler. You can extract the values from the arguments to detect
the type of movement and the values, as shown in the following code example. Scale values are generated by pinch or stretch gestures and
are generally used to resize objects. Translation values are generated by movement over the screen, and are generally used to move objects.

C#
// Raised when the gesture starts. Typically used only to detect
// tap events, or to start a timer if you want to differentiate
// tap and double-tap events.
void PhoneApplicationPage_ManipulationStarted(object sender,
ManipulationStartedEventArgs e)
{
double xStartCoordinate = e.ManipulationOrigin.X;
double yStartCoordinate = e.ManipulationOrigin.Y;
}
// Raised repeatedly during the gesture. Can be used to
// provide dynamic visual feedback to the user.
void PhoneApplicationPage_ManipulationDelta(object sender,
ManipulationDeltaEventArgs e)
{
double xScale = e.DeltaManipulation.Scale.X;
double yScale = e.DeltaManipulation.Scale.Y;
double xTranslation = e.DeltaManipulation.Translation.X;
double yTranslation = e.DeltaManipulation.Translation.Y;
}
// Raised when the gesture ends. The original start position
// is available as well as the relative scale and translation
// values and information about the gesture velocities.
void PhoneApplicationPage_ManipulationCompleted(object sender,
ManipulationCompletedEventArgs e)
{
double xStartOrigin = e.ManipulationOrigin.X;
double yStartOrigin = e.ManipulationOrigin.Y;
double xTotalScale = e.TotalManipulation.Scale.X;
double yTotalScale = e.TotalManipulation.Scale.Y;
double xTotalTranslation = e.TotalManipulation.Translation.X;
double yTotalTranslation = e.TotalManipulation.Translation.Y;
double xExpansionVelocity =
e.FinalVelocities.ExpansionVelocity.X;
double yExpansionVelocity =
e.FinalVelocities.ExpansionVelocity.Y;
double xLinearVelocity = e.FinalVelocities.LinearVelocity.X;
double yLinearVelocity = e.FinalVelocities.LinearVelocity.Y;
}

For more information about using the Silverlight manipulation events, see “Gesture Support for Windows Phone” (http://msdn.
microsoft.com/en-us/library/ff967546(VS.92).aspx) and “How to: Handle Manipulation Events” (http://msdn.microsoft.com/en-us/library/ff426933(VS.95).aspx) on MSDN.

Gesture Detection Using the GestureListener Control

If you simply need to detect the full range of gestures and the basic position, scale, and translation information, you should consider using
the GestureListener control that is included in the Silverlight for Windows Phone Toolkit. This control makes it easy to handle the full range of gesture events, including Tap, Double-tap, Hold, Drag, Flick, and Pinch. You can obtain the Silverlight for Windows Phone Toolkit
from the Silverlight Toolkit website on CodePlex (http://silverlight.codeplex.com/).

To use the GestureListener control, you must reference the assembly Microsoft.Phone.Controls.Toolkit in your project and add
the control to a page in your application. The following example shows the control inserted into a Grid that covers the complete page,
except for the page title area.

XAML

<Grid x:Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″
Background=”Black”>
<Grid.OpacityMask>
<SolidColorBrush />
</Grid.OpacityMask>
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener
Tap=”OnTap”
DoubleTap=”OnDoubleTap”
Hold=”OnHold”
DragStarted=”OnDragStarted”
DragDelta=”OnDragDelta”
DragCompleted=”OnDragCompleted”
Flick=”OnFlick”
PinchStarted=”OnPinchStarted”
PinchDelta=”OnPinchDelta”
PinchCompleted=”OnPinchCompleted”/>
</toolkit:GestureService.GestureListener>
</Grid>

Notice that the properties of the GestureListener allow you to specify individual event handlers for each detected event. The
GestureListener control effectively wraps the XNA gesture detection mechanism and performs automatic conversion of the XNA
events into individual Silverlight events for each gesture type.

The following code example shows the event handlers and the values you can obtain for each type of event detected by the control.
Note that the control may raise a combination of events for some gestures. For example, it may raise the Drag events during a flick gesture
and when the flick gesture completes.

C#
private void OnTap(object sender, GestureEventArgs e)
{
// Get the screen position relative to the page.
double xPosition = e.GetPosition(this).X;
double yPosition = e.GetPosition(this).Y;
}
private void OnDoubleTap(object sender, GestureEventArgs e)
{
double xPosition = e.GetPosition(this).X;
double yPosition = e.GetPosition(this).Y;
}
private void OnHold(object sender, GestureEventArgs e)
{
double xPosition = e.GetPosition(this).X;
double yPosition = e.GetPosition(this).Y;
}
// This is raised when a drag gesture starts.
private void OnDragStarted(object sender,
DragStartedGestureEventArgs e)
{
double xPosition = e.GetPosition(this).X;
double yPosition = e.GetPosition(this).Y;
}
// This is raised repeatedly during a drag gesture.
private void OnDragDelta(object sender, DragDeltaGestureEventArgs e)
{
double xOriginalPosition = e.GetPosition(this).X;
double yOriginalPosition = e.GetPosition(this).Y;
double xMovement = e.HorizontalChange;
double yMovement = e.VerticalChange;
}
// This is raised when a drag gesture completes.
private void OnDragCompleted(object sender,
DragCompletedGestureEventArgs e)
{
double xOriginalPosition = e.GetPosition(this).X;
double yOriginalPosition = e.GetPosition(this).Y;
double xMovement = e.HorizontalChange;
double yMovement = e.VerticalChange;
double xVelocity = e.HorizontalVelocity;
double yVelocity = e.VerticalVelocity;
}
// This is raised in conjunction with Drag events
// after a flick gesture completes.
private void OnFlick(object sender, FlickGestureEventArgs e)
{
double xPosition = e.GetPosition(this).X;
double yPosition = e.GetPosition(this).Y;
double angle = e.Angle;
double xVelocity = e.HorizontalVelocity;
double yVelocity = e.VerticalVelocity;
}
// This is raised when a pinch or zoom gesture starts.
private void OnPinchStarted(object sender,
PinchStartedGestureEventArgs e)
{
double xPosition = e.GetPosition(this).X;
double yPosition = e.GetPosition(this).Y;
double distance = e.Distance;
double angle = e.Angle;
}
// This is raised repeatedly during a pinch or zoom gesture.
private void OnPinchDelta(object sender, PinchGestureEventArgs e)
{
double xOriginalPosition = e.GetPosition(this).X;
double yOriginalPosition = e.GetPosition(this).X;
double distance = e.DistanceRatio;
double angle = e.TotalAngleDelta;
}
// This is raised when a pinch or zoom gesture completes.
private void OnPinchCompleted(object sender,
PinchGestureEventArgs e)
{
double xOriginalPosition = e.GetPosition(this).X;
double yOriginalPosition = e.GetPosition(this).X;
double distance = e.DistanceRatio;
double angle = e.TotalAngleDelta;
}

For more information and to download the Silverlight for Windows Phone Toolkit, see the Silverlight Toolkit page on CodePlex (http://silverlight.codeplex.com/).

Gesture Detection Using XNA

To detect touch and gestures using the XNA Framework classes, you must do the following:

  • Add a reference to the assemblies Microsoft.Xna.Framework and Microsoft.Xna.Framework.Input.Touch to your project.
  • Set the properties of the static TouchPanel class to specify the types of gestures you want to capture.
  • Start a DispatcherTimer that will raise an event at appropriate intervals.
  • Handle the event raised by the DispatcherTimer to obtain the gesture information.

The following code example specifies that the TouchPanel will collect all gestures except for horizontal drag and vertical drag (which
constrain the results in one direction). It then creates a Dispatcher Timer with an interval of 50 milliseconds, though you can vary this
depending on how often you want to read gesture information, adds the event handler, and starts the timer. To use this code, you must
reference the namespace System.Windows.Threading.

C#
TouchPanel.DisplayHeight = 800;
TouchPanel.DisplayWidth = 480;
TouchPanel.EnabledGestures = GestureType.Tap |
GestureType.DoubleTap |
GestureType.Hold |
GestureType.FreeDrag |
GestureType.Flick |
GestureType.Pinch;
var touchTimer = new DispatcherTimer();
touchTimer.Interval = TimeSpan.FromMilliseconds(50);
touchTimer.Tick += new EventHandler(Read_Gestures);
touchTimer.Start();

In the event raised by the timer, you can read each gesture. However, each gesture will consist of several individual components; for
example, a double tap will result in detection of both a tap and a double tap gesture, so your code must examine the sequence of gestures
to determine what action to take.

The following code example of a gesture detection event handler shows how you obtain information about each gesture that was detected.
It indicates the values that are available for each of the gesture types. Remember that the event handler runs on a different thread from the UI, so you must invoke a method on the UI thread if you want to update the UI with the discovered values.

C#
public void Read_Gestures(object sender, EventArgs e)
{
float xCoordinate = 0;
float yCoordinate = 0;
float xStartCoordinate = 0;
float yStartCoordinate = 0;
float xEndCoordinate = 0;
float yEndCoordinate = 0;
float xSecondFingerStartCoordinate = 0;
float ySecondFingerStartCoordinate = 0;
float xSecondFingerEndCoordinate = 0;
float ySecondFingerEndCoordinate = 0;
float xFlickSpeed = 0;
float yFlickSpeed = 0;
while (TouchPanel.IsGestureAvailable)
{
GestureSample gesture = TouchPanel.ReadGesture();
switch (gesture.GestureType)
{
case GestureType.Tap:
xCoordinate = gesture.Position.X;
yCoordinate = gesture.Position.Y;
break;
case GestureType.DoubleTap:
xCoordinate = gesture.Position.X;
yCoordinate = gesture.Position.Y;
break;
case GestureType.Hold:
xCoordinate = gesture.Position.X;
yCoordinate = gesture.Position.Y;
break;
case GestureType.FreeDrag:
xEndCoordinate = gesture.Position.X;
yEndCoordinate = gesture.Position.Y;
xStartCoordinate = xEndCoordinate – gesture.Delta.X;
yStartCoordinate = yEndCoordinate – gesture.Delta.Y;
// For GestureType.HorizontalDrag, Delta.Y
// will always be zero.
// For GestureType.VerticalDrag, Delta.X
// will always be zero.
break;
case GestureType.Flick:
xFlickSpeed = gesture.Delta.X; // pixels per second
yFlickSpeed = gesture.Delta.Y; // pixels per second
break;
case GestureType.Pinch:
xEndCoordinate = gesture.Position.X;
yEndCoordinate = gesture.Position.Y;
xStartCoordinate = xEndCoordinate – gesture.Delta.X;
yStartCoordinate = yEndCoordinate – gesture.Delta.Y;
xSecondFingerStartCoordinate = gesture.Position2.X;
ySecondFingerStartCoordinate = gesture.Position2.Y;
xSecondFingerEndCoordinate = xSecondFingerStartCoordinate
– gesture.Delta2.X;
ySecondFingerEndCoordinate = ySecondFingerStartCoordinate
– gesture.Delta2.Y;
break;
}
}
}

For more information about using XNA to detect gestures, see “Working with Touch Input (Windows Phone)” on MSDN (http://
msdn.microsoft.com/en-us/library/ff434208.aspx).