Programming4us
         
 
 
Windows Phone

Programming Windows Phone 7: An Introduction to Touch - Low-Level Touch Events in Silverlight

1/20/2011 7:42:52 PM
Like XNA, Silverlight also supports two different programming interfaces for working with multi-touch, which can be most easily categorized as low-level and high-level. The low-level interface is based around the static Touch.FrameReported event, which is very similar to the XNA TouchPanel except that it’s an event and it doesn’t include gestures.

The high-level interface consists of three events defined by the UIElement class: ManipulationStarted, ManipulationDelta, and ManipulationCompleted. The Manipulation events, as they’re collectively called, consolidate the interaction of multiple fingers into movement and scaling factors.

The core of the low-level touch interface in Silverlight is a class called TouchPoint, an instance of which represents a particular finger touching the screen. TouchPoint has four get-only properties:

  • Action of type TouchAction, an enumeration with members Down, Move, and Up.

  • Position of type Point, relative to the upper-left corner of a particular element. Let’s call this element the reference element.

  • Size of type Size. This is supposed to represent the touch area (and, hence, finger pressure, more or less) but Windows Phone 7 doesn’t return useful values.

  • TouchDevice of type TouchDevice.

The TouchDevice object has two get-only properties:

  • Id of type int, used to distinguish between fingers. A particular finger is associated with a unique Id for all events from Down through Up.

  • DirectlyOver of type UIElement, the topmost element underneath the finger.

As you can see, the Silverlight TouchPoint and TouchDevice objects give you mostly the same information as the XNA TouchLocation object, but the DirectlyOverproperty of TouchDevice is often very useful for determining what element the user is touching.

To use the low-level touch interface, you install a handler for the static Touch.FrameReported event:

Touch.FrameReported += OnTouchFrameReported;

The OnTouchFrameReported method looks like this:

void OnTouchFrameReported(object sender, TouchFrameEventArgs args)
{
. . .
}

The event handler gets all touch events throughout your application. The TouchFrameEventArgs object has a TimeStamp property of type int, plus three methods:

  • GetTouchPoints(refElement) returns a TouchPointCollection

  • GetPrimaryTouchPoint(refElement) returns one TouchPoint

  • SuspendMousePromotionUntilTouchUp()

In the general case, you call GetTouchPoints, passing to it a reference element. The TouchPoint objects in the returned collection have Position properties relative to that element. You can pass null to GetTouchPoints to get Position properties relative to the upper-left corner of the application.

The reference element and the DirectlyOver element have no relationship to each other. The event always gets all touch activity for the entire program. Calling GetTouchPoints or GetPrimaryTouchPoints with a particular element does not limit the events to only those events involving that element. All that it does is cause the Position property to be calculated relative to that element. (For that reason, Position coordinates can easily be negative if the finger is to the left of or above the reference element.) The DirectlyOver element indicates the element under the finger.

A discussion of the second and third methods requires some background: The Touch.FrameReported event originated on Silverlight for the desktop, where it is convenient for the mouse logic of existing controls to automatically use touch. For this reason, touch events are “promoted” to mouse events.

But this promotion only involves the “primary” touch point, which is the activity of the first finger that touches the screen when no other fingers are touching the screen. If you don’t want the activity of this finger to be promoted to mouse events, the event handler usually begins like this:

void OnTouchFrameReported(object sender, TouchFrameEventArgs args)
{
TouchPoint primaryTouchPoint = args.GetPrimaryTouchPoint(null);

if (primaryTouchPoint != null && primaryTouchPoint.Action == TouchAction.Down)
{
args.SuspendMousePromotionUntilTouchUp();
}
. . .
}

The SuspendMousePromotionUntilTouchUp method can only be called when a finger first touches the screen when no other fingers are touching the screen.

On Windows Phone 7, such logic presents something of a quandary. As written, it basically wipes out all mouse promotion throughout the application. If your phone application incorporates Silverlight controls that were originally written for mouse input but haven’t been upgraded to touch, you’re basically disabling those controls.

Of course, you can also check the DirectlyOver property to suspend mouse promotion selectively. But on the phone, no elements should be processing mouse input except for those controls that don’t process touch input! So it might make more sense to never suspend mouse promotion.

I’ll leave that matter for your consideration and your older mouse-handling controls. Meanwhile, the program I want to write is only interested in the primary touch point when it has a TouchAction of Down, so I can use that same logic.

The SilverlightTouchHello project has a TextBlock in the XAML file:Silverlight Project:

Example 1. SilverlightTouchHello File: MainPage.xaml (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock Name="txtblk"
Text="Hello, Windows Phone 7!"
Padding="0 34"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>

Notice the Padding value. I know that the font displayed here has a FontSize property of 20 pixels, which actually translates into a TextBlock that is about 27 pixels tall. I also know that it’s recommended that touch targets not be smaller than 9 millimeters. If the resolution of the phone display is 264 DPI, then 9 millimeters is 94 pixels. (The calculation is 9 millimeters divided by 25.4 millimeters to the inch, times 264 pixels per inch.) The TextBlock is short by 67 pixels. So I set a Padding value that puts 34 more pixels on both the top and bottom (but not the sides).

I used Padding rather than Margin because Padding is space inside the TextBlock. The TextBlock actually becomes larger than the text size would imply. Margin is space outside the TextBlock. It’s not part of the TextBlock itself and is excluded for purposes of hit-testing.

Here’s the complete code-behind file. The constructor of MainPage installs the Touch.FrameReported event handler.

Example 2. Silverlight Project: SilverlightTouchHello File: MainPage.xaml.cs
using System;
using System.Windows.Input;
using System.Windows.Media;
using Microsoft.Phone.Controls;

namespace SilverlightTouchHello
{
public partial class MainPage : PhoneApplicationPage
{
Random rand = new Random();
Brush originalBrush;

public MainPage()
{
InitializeComponent();
originalBrush = txtblk.Foreground;
Touch.FrameReported += OnTouchFrameReported;
}

void OnTouchFrameReported(object sender, TouchFrameEventArgs args)
{
TouchPoint primaryTouchPoint = args.GetPrimaryTouchPoint(null);

if (primaryTouchPoint != null && primaryTouchPoint.Action == TouchAction.
Down)
{
if (primaryTouchPoint.TouchDevice.DirectlyOver == txtblk)
{
txtblk.Foreground = new SolidColorBrush(
Color.FromArgb(255, (byte)rand.Next(256),
(byte)rand.Next(256),
(byte)rand.Next(256)));
}
else
{
txtblk.Foreground = originalBrush;
}
}
}
}
}


The event handler is only interested in primary touch points with an Action of Down. If the DirectlyOver property is the element named txtblk, a random color is created. Unlike the Color structure in XNA, the Silverlight Color structure doesn’t have a constructor to set a color from red, green, and blue values, but it does have a static FromArgb method that creates a Color object based on alpha, red, green, and blue values, where alpha is opacity. Set the alpha channel to 255 to get an opaque color. Although it’s not obvious at all in the XAML files, the Foreground property is actually of type Brush, an abstract class from which SolidColorBrush descends.

If DirectlyOver is not txtblk, then the program doesn’t change the color to white, because that wouldn’t work if the user chose a color theme of black text on a white background. Instead, it sets the Foreground property to the brush originally set on the TextBlock. This is obtained in the constructor.

Other -----------------
- Windows Phone 7: Composing a New Message
- Programming Windows Phone 7: An Introduction to Touch - The XNA Gesture Interface
- Programming Windows Phone 7: An Introduction to Touch - Low-Level Touch Handling in XNA
- Windows Phone 7: Responding to a Message
- Windows Phone 7: Checking for New Messages
- Windows Phone 7: Sorting and Searching Your Mail
- Windows Phone 7: Customizing Your Contacts List
- Windows Phone 7: Working with the Me Card
- Windows Phone 7: Posting to Facebook or Windows Live
- Programming Windows Phone 7 : Simple Clocks (part 2)
- Programming Windows Phone 7 : Simple Clocks (part 1)
- Windows Phone7: Pinning a Contact to Start
- Windows Phone7: Adding a Picture or Ringtone to a Contact
- Windows Phone7: Deleting a Contact
- Programming Windows Phone 7: XNA Orientation
- Programming Windows Phone 7: Orientation Events
- Windows Phone 7: Editing a Contact
- Windows Phone 7: Finding a Contact
- Windows Phone 7: Adding a Contact
- Windows Phone 7: Linking Contacts
 
 
Most View
- jQuery 1.3 : Sorting and paging (part 2) - JavaScript sorting
- Windows Server 2008 : Deploying a Terminal Server (part 2) - Specifying NLA Settings
- Windows XP : Participating in Internet Newsgroups - Some Usenet Basics (part 2) - Setting Up a News Account
- Microsoft Exchange Server 2003: Configuring Information Stores (part 2) - Moving Exchange Server 2003 Storage Groups and Databases
- Windows 7 : Installing Internet Information Services
- Using Non-Windows Systems to Access Exchange Server 2007 : Outlook Express
- ASP.NET 4 in VB 2010 : Site Maps (part 1) - Defining a Site Map
- SQL Server 2008: Administering Database Objects - Working with Tables (part 2) - Primary Key Constraints & Unique Constraints
- First Stages of SEO : Defining Your Site’s Information Architecture
- What's New in SharePoint 2013 (part 2) - THE APP MODEL
Top 10
- Implementing Edge Services for an Exchange Server 2007 Environment : Utilizing the Basic Sender and Recipient Connection Filters (part 3) - Configuring Recipient Filtering
- Implementing Edge Services for an Exchange Server 2007 Environment : Utilizing the Basic Sender and Recipient Connection Filters (part 2)
- Implementing Edge Services for an Exchange Server 2007 Environment : Utilizing the Basic Sender and Recipient Connection Filters (part 1)
- Implementing Edge Services for an Exchange Server 2007 Environment : Installing and Configuring the Edge Transport Server Components
- What's New in SharePoint 2013 (part 7) - BCS
- What's New in SharePoint 2013 (part 6) - SEARCH
- What's New in SharePoint 2013 (part 6) - WEB CONTENT MANAGEMENT
- What's New in SharePoint 2013 (part 5) - ENTERPRISE CONTENT MANAGEMENT
- What's New in SharePoint 2013 (part 4) - WORKFLOWS
- What's New in SharePoint 2013 (part 3) - REMOTE EVENTS