LightTouch Enhancements–Popups and “Layered” Controls

While I am actively working on adding new functionality to the LightTouch library (such as adding the Pinch Gesture to bring parity with the GestureListener for Windows Phone from the Silverlight for Windows Phone Toolkit) for an upcoming release, a couple of issues came to light that made adding a new release appropriate.  As the title of this post suggests, these issues relate to support for touch in Popups (especially ChildWindow controls) and for controls where different layers of the control’s visual tree make use of different behaviors.

Support for Popups / Child Windows

At the heart of LightTouch is the Manipulation2DBehavior.  Much of the functionality behind this behavior is discussed here.  One of the basic methods’ responsibilities is to determine, based on the coordinates of the touch event, what controls are under that point and which of those controls have the Manipulation2DBehavior attached.  To do this lookup, the VisualTreeHelper.FindElementsInHostCoordinates function is used, with Application.Current.RootVisual supplied for the relative UIElement.  This is where difficulty with popups occurred.  Popup controls exist outside of the Visual Tree of the application’s RootVisual.  This can be seen in the following UI, with its Visual Tree as reported by Silverlight Spy.  Note how the Popup control appears as a sibling to the MainPage element.

image

image

So in order to locate the controls with behaviors in the popup, we have to use the Popup as the relative UIElement for the call to VisualTreeHelper.FindElementsInHostCoordinates.  Now to find the popup in the Visual Tree…this can be accomplished with the VisualTreeHelper.GetOpenPopups call.  Unfortunately, this call does not document how the list is populated relative to the Z-order of the ChildWindow (in case multiple ChildWindows are being displayed, issues of UI-propriety with this approach notwithstanding.)  Empirically, it seems that the topmost child window (if present) is the first in the list, so if any ChildWindows are being shown, we locate the first one in the list, and use it as the argument to FindElementsInHostCoordinates.  From there on, things progress as they had previously.

Supporting “Layers”

Shrek: “NO!  Layers.  Onions have layers.  Ogres have layers.   Onions have layers.  You get it?  We both have layers”
Donkey: “Oh, you both have layers.  Oh.  You know, not everybody likes onions.  What about cake?  Everybody loves cake!”
- Shrek (2001)

So what do I mean about layers?  In this case, I am referring to a situation where multiple related controls under a given point in a visual tree have Manipulation Behaviors attached.  An example would be a ListBox control with the ListBoxTouchScrollBehavior attached, and the underlying data template for the items in the list box having a GestureListener attached with a handler for a DoubleTap event.  The original implementation stopped at the first matching behavior, resulting in the ListBox scrolling, but ignoring the DoubleTap event.  The new implementation now identifies and processes all Manipulations under the given touch point.  This is similar to a Bubbling event, with a couple of key differences.  First, there is no notion of “handled.”  Second, the relationships do not have to exist in common branches of the same visual tree.

Available for Download

The latest code is up on CodePlex and the Alpha-2 release has been built based on these changes, which can be downloaded here.  I hope people find it helpful.

New Hampshire .Net (Seacoast) User Group Presentation Materials

I have uploaded the content from my Introduction to Windows Phone 7 Development with Silverlight talk at the New Hampshire .Net Seacoast User Group meeting last night in Portsmouth. The content can be found here, and includes:

  • Presentation slides, which include the reference links I mentioned during the talk.
  • The sample code, broken into 2 projects. Because the Notification Services portion of the talk adds extra projects to the solution ad is a little more complex to build and launch, that portion has been broken out into its own separate zip file.

For the Notification Services portion of the demo, the web project should be launched first, followed by the phone project (since the phone app calls the web site to register its URL for receiving notifications.) If the solution is run with the web project set as the default start project, the application bits do get deployed to the phone, but the debugger is not hooked up (unless multiple startup projects are used.) If debugging of the phone app is desired, it can be achieved by right clicking on the phone project and selecting Debug / Start New Instance. Also, this time the Notification Services demo includes the Push Notification Server-Side Helper recipe.

As usual, I have “sanitized” the uploaded code content by removing my personal Bing Maps application key. For information on how to obtain your own map key, please check out the Bing Maps Developer Portal.

I have also added a project that  shows the technique for “immediately” updating the application’s tile via a temporary Notification Services endpoint.  This is based on the code first presented here

The posted Slide Deck includes the slides that call out new content in the upcoming “Mango” release of WP7, and I have edited one slide to include one IMPORTANT new addition to the phone SDK that I forgot to previously include – support for Sockets.

Many thanks to Pat Tormey for inviting me to be the inaugural speaker for this new user group, as well as to Mark Mullin and Global Relief Technologies for providing a great site.  Also many thanks are deserved by the attendees, who asked some of the best questions I have gotten since I started doing these talks.

New for Windows Phone (Now) – the Async CTP

As is often the case when big events happen, sometimes some important announcements can get overlooked and/or overshadowed.  Mix 2011 certainly featured big news, including Silverlight 5 Beta, the Windows Phone 7.5 features, IE10, and the latest in the MVC framework.  However, in all of the hoopla, the release of the SP1 refresh of the Microsoft Visual Studio Async CTP SP1 Refresh, as well as some of the important changes, may have gone unnoticed.

There are a few important things to note regarding the Async CTP Refresh:

  • It includes an “As-Is” Go-Live license for use in production environments (albeit with some stern warnings about why you should really consider NOT using it in production code.)
  • It includes support for .Net, Silverlight 4, and Windows Phone 7.0.

Let me restate that last point.  The Async CTP works with Windows Phone 7 today.  No need to wait for the Mango update.

Now Just “await” a Minute…

As a CTP, and with the “As Is” license, there is no guarantee that this will eventually make it into the framework, and even if it does, it may take a very different form.  That being said, it is a great opportunity to see where things are headed and to offer feedback to the development team as to how to best shape this functionality to be as useful as it can be. 

That’s Nice.  How Long do I have to “await” to See Some Code?

So what do the Async tools bring to the table?  Among other things, it allows asynchronous code to be written without the “disruption” that currently occurs when that is being done today.  While a full discussion of asynchrony and the problems it solves and the new ones it presents are beyond the scope of this discussion, some brief coverage is merited.  Writing synchronous code today follows the pattern of “do something, wait for it to finish, then proceed.”  Altering this to be asynchronous (often) changes the pattern either the Asynchronous Programming Model/APM (“Call BeginXXX to start the operation, then EndXXX to wait for it to be completed”) or to the Event-Asynchronous Pattern/EAP (“start doing something, and raise an event that I am listening for when you are done.”)  When the completion of one asynchronous operation needs to trigger another one, code can get complicated and messy.  This situation is particularly apparent to those who use Silverlight and the related Silverlight for Windows Phone, as all I/O operations in Silverlight are inherently asynchronous.  The Async CTP brings a third model – the Task-based Asynchronous Pattern/TAP. 

The TAP model features the use of the async and await keywords to allow asynchronous code to be written in a much more linear fashion.  Under the covers, the compiler will generate all of the necessary “goo”, allowing the development to focus on the problem at a higher level.  The following code may help to visualize what this all means.

In the code that follows, a WebClient is spun up to return the data at a given URL.  The number of bytes in that data is returned as the result of the function.  This is the synchronous version of the code.

Code Snippet
  1. private void button1_Click(object sender, RoutedEventArgs e)
  2. {
  3.     var count = DoSomething();
  4.     MessageBox.Show(count.ToString());
  5. }
  6.  
  7. private Int32 DoSomething()
  8. {
  9.     var webClient = new WebClient();
  10.     var data = webClient.DownloadString(new Uri("http://www.wintellect.com/Consulting/Consultants/John-Garland"));
  11.     var results = data.Length;
  12.     return results;
  13. }

Note that this code blocks the UI when called, and cannot be used in Silverlight or Silverlight for Windows Phone applications.  So what if you don’t want to block the UI while retrieving the information (or better yet, what if you cannot, as is the case with Silverlight?)  Bring in asynchrony, but notice how it changes the nature of the function.  Where the desire had been to call a function to retrieve a result, now the function is called to eventually signal a response, which must be subscribed to by the calling code.

Code Snippet
  1. private void DoSomethingEAP()
  2. {
  3.     var webClient = new WebClient();
  4.     webClient.DownloadDataCompleted += HandleWebClientDownloadDataCompleted;
  5.     webClient.DownloadStringAsync(new Uri("http://www.wintellect.com/Consulting/Consultants/John-Garland"));
  6. }
  7.  
  8. private void HandleWebClientDownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
  9. {
  10.     var data = e.Result.Length;
  11.     MessageBox.Show(data.ToString());
  12. }

This is somewhat compressed and contained when inline lambda expressions are brought to bear, but the fundamental problem still exists.  The function has been modified because of its asynchronous implementation. 

Code Snippet
  1. private void DoSomethingEAPLambda()
  2. {
  3.     var webClient = new WebClient();
  4.     webClient.DownloadDataCompleted += (o, e) =>
  5.     {
  6.         var data = e.Result.Length;
  7.         MessageBox.Show(data.ToString());
  8.     };
  9.     webClient.DownloadStringAsync(new Uri("http://www.wintellect.com/Consulting/Consultants/John-Garland"));
  10. }

Now lets see how using the Async tools change things. 

Code Snippet
  1. private async void button1_Click(object sender, RoutedEventArgs e)
  2. {
  3.     var count = await DoSomethingAsync();
  4.     MessageBox.Show(count.ToString());
  5. }
  6.  
  7. private async Task<Int32> DoSomethingAsync()
  8. {
  9.     var webClient = new WebClient();
  10.     var data = await webClient.DownloadStringTaskAsync(new Uri("http://www.wintellect.com/Consulting/Consultants/John-Garland&quot;));
  11.     var results = data.Length;
  12.     return results;
  13. }

Note that the functions now much more closely resemble the initial synchronous version. 

I’m Tired of “awaiting”.  Get Me the Bits.

This was just a light overview.  There are many other combinations and applications for the TAP.  Hopefully, this was enough to pique some curiosity.  If interested, the download for the Microsoft Visual Studio Async CTP SP1 Refresh is available at http://msdn.microsoft.com/en-us/vstudio/async.  This includes documentation, samples, and walkthroughs.  The tools require Visual Studio 2010 SP1.  Check out Eric Lippert’s announcement of the release (and additional links) at http://blogs.msdn.com/b/ericlippert/archive/2011/04/13/refreshing-the-async-ctp.aspx.

Enhanced Touch Manipulations for Silverlight and Windows Phone

Following up on Jeff’s series on Touch Interfaces for Windows Phone, I wanted to show an additional technique that allows support for Manipulations in Silverlight. Furthermore, when this is extended to the Phone, it allows support for moving two or more UI elements independently, which as Jeff noted, is not possible with the Manipulation events exposed in Silverlight for Windows Phone.
The article by Charles Petzold that Jeff refers to discusses the fact that while Manipulation events are present in Silverlight 4, they are not available for use. Attempts to hook these events either in code or in markup will result in a runtime exception. The good news is that there is a downloadable assembly that, with some additional work on the developers’ part, can provide the benefits of Manipulations to Silverlight 4 applications. This assembly is available as part of the Microsoft Surface Manipulations and Inertia Sample for Microsoft Silverlight, which is available for download here. The download includes the System.Windows.Input.Manipulations.dll assembly (hereafter the “Manipulations Assembly”) and a sample application, including code, which offers guidance as to how it can be used.
The Manipulations Assembly is a Silverlight version of the equivalent assembly included in .Net 4.0, and exposes a set of manipulation and inertia-related classes. Besides the inclusion of the letters “2D” in the name of each of the namespace members, these items work together to provide functionality that is similar to what Jeff described. Documentation for these elements is available at http://msdn.microsoft.com/en-us/library/system.windows.input.manipulations(VS.100).aspx.
As I mentioned above, using the Manipulation2D classes will require some additional work. Specifically, your code will need to provide input to the manipulation engine, provided by the ManipulationProcessor2D class, converting events of your choosing into individual manipulation actions and indicating when a particular manipulation has been completed. The manipulation engine will take that input and convert it into the appropriate Started, Delta, and Completed events, including calculating offsets, velocities, etc.
With respect to Christopher Walken, “Enough talkie-talkie, more ping-pong” (Let’s see some code!)
First we’ll start with a Silverlight 4.0 project and add a reference to the Manipulations Assembly (locate the folder the content was downloaded and extracted into from the link above.) As has been discussed, Silverlight UIElements expose several Manipulation events, none of which can be used. However, it would be handy if the Manipulations Assembly could be used to simulate the presence of those events on these types of objects. So we turn to Behaviors, with the intent of providing a behavior that allows us to raise these events out of instances of UIElements in our markup. This means we also need a reference to System.Windows.Interactivity.dll.
clip_image002
Moving from Touches to Manipulations
Once we have our references figured out, we can get to work. As I mentioned above, one of the caveats of working with the Manipulations Assembly is that some extra work is required. Specifically, you need to catch the application-wide Touch events and then feed them to the classes in the Manipulations Assembly. That’s a multi-step process, because Touch events are application-wide and we want manipulations to appear as if they were sourced from individual UIElements. So step 1 is to hook the touch events when the behavior is attached to its UIElement.
First when the behavior is attached:
Code Snippet
  1. protected override void OnAttached()
  2. {
  3. base.OnAttached();
  4. HookTouchEvents();
  5. HookMouseEvents();
  6. _subscribedBehaviors.Add(this);
  7. }
And the actual event subscription:
Code Snippet
  1. private static void HookTouchEvents()
  2. {
  3. if (!_touchEventsHooked)
  4. {
  5. _touchEventsHooked = true;
  6. System.Windows.Input.Touch.FrameReported += OnFrameReported;
  7. }
  8. }
There are two important things to note here. First, when attaching the behavior, the current instance is being added to a static list of attached behaviors (and removed from the list in the OnDetaching override)…more on this in a minute. Also, notice that the Touch events are only being hooked per type, instead of per class. This prevents the touch event from firing once per behavior instance.
The majority of the hard work happens in the OnFrameReported handler and the associated ProcessTouchPoints method, which does three key processing steps.
First, it identifies any new touch-point/behavior associations:
Code Snippet
  1. // Find any new touch-point/behavior associations.
  2. foreach (var touchPoint in touchPoints.Where(x => x.Action == TouchAction.Down))
  3. {
  4. // There shouldn’t be any of these!
  5. if (!_capturedBehaviors.ContainsKey(touchPoint.DeviceId))
  6. {
  7. // “Unowned” touch device – see if a behavior can be found for it to associate with at its current position…
  8. var matchingBehavior = GetBehaviorAssociatedWithTouchPoint(touchPoint.Position, _subscribedBehaviors);
  9. if (matchingBehavior != null)
  10. {
  11. _capturedBehaviors.Add(touchPoint.DeviceId, matchingBehavior);
  12. }
  13. }
  14. }
This is done by examining all of the incoming touch points for those whose action type is “Down.” For each of those touch points, we check to find any UIElements with an associated behavior that are directly under the touchpoint. For this, we use the VisualTreeHelper.FindElementsInHostCoordinates call and iterate over those elements to see if they match the AssociatedObject of any of the behaviors that are in the list that we maintain when attaching/detaching the behaviors.
Code Snippet
  1. private static Manipulate2DBehavior GetBehaviorAssociatedWithTouchPoint(Point touchPointPosition, IEnumerable<Manipulate2DBehavior> behaviorsToCheck)
  2. {
  3. Manipulate2DBehavior result = null;
  4. IEnumerable<UIElement> elements = VisualTreeHelper.FindElementsInHostCoordinates(touchPointPosition, Application.Current.RootVisual);
  5. foreach (var element in elements)
  6. {
  7. result = behaviorsToCheck.FirstOrDefault(x => x.AssociatedObject == element);
  8. if (result != null) break;
  9. }
  10. return result;
  11. }
If a matching behavior is found, it is considered to be “captured” and is added to a static dictionary that gathers the touchpoint’s DeviceId and the behavior. This step is what actually enables us to track multiple concurrent manipulations, as we are not able to react to multiple “captured” manipulations, as will be explained shortly.
The next step in the Touch Point processing is to actually process the touch events for all of the captured behaviors. This includes those who were just gathered in the previous step, as well as any previous touches for which a touch-down has been received without a touch-up to end it.
Code Snippet
  1. // Process any current touch-point/behaviors
  2. foreach (var capturedBehavior in _capturedBehaviors.Values.Distinct())
  3. {
  4. var associatedTouchDeviceIds = _capturedBehaviors.Where(x => x.Value == capturedBehavior).Select(x => x.Key);
  5. var associatedTouchPoints = touchPoints.Where(x => associatedTouchDeviceIds.Contains(x.DeviceId));
  6. capturedBehavior.HandleTouchEvents(associatedTouchPoints);
  7. }
To do this, the current list of touch points associated with any one behavior (in case multiple fingers are touching the same UIElement) are passed to the capturedBehavior’s HandleTouchEvents method.
Code Snippet
  1. private void HandleTouchEvents(IEnumerable<TouchEventData> points)
  2. {
  3. IEnumerable<Manipulator2D> manips = points.Select(p => new Manipulator2D
  4. {
  5. Id = p.DeviceId,
  6. X = p.PositionX,
  7. Y = p.PositionY
  8. });
  9. _manipulationProcessor.ProcessManipulators(DateTime.Now.Ticks, manips);
  10. }
The HandleTouchEvents method introduces an instance of the Manipulation2DProcessor, which is the “engine” that drives the manipulation calculations. Every instance of the behavior class has its own instance of the Manipulation2DProcessor called _manipulationProcessor that is responsible for handling the manipulation inputs (via the Manupulator2D class and ProcessManipulators method), as well as raising the appropriate manipulation events. Once the correct behavior (and hence Manipulation2DProcessor instance) is determined from the location of the input touchpoints, those touchpoints can be provided to the manipulation engine for it to handle the rest.
The final task of the ProcessTouchPoints method is to remove any “captured” behaviors based on the corresponding touchpoint TouchUp actions.
Code Snippet
  1. // Find and remove touch point/behavior associations as needed
  2. foreach (var touchPoint in touchPoints.Where(x => x.Action == TouchAction.Up))
  3. {
  4. if (_capturedBehaviors.ContainsKey(touchPoint.DeviceId))
  5. {
  6. var matchingBehavior = _capturedBehaviors[touchPoint.DeviceId];
  7. _capturedBehaviors.Remove(touchPoint.DeviceId);
  8. if (!_capturedBehaviors.ContainsValue(matchingBehavior))
  9. {
  10. //That was the last device holding on to the specific behavior…
  11. matchingBehavior.CompleteManipulation();
  12. }
  13. }
  14. }
For each touchpoint whose action is “Up”, the corresponding touchpoint/behavior entry is removed from the “captured” dictionary. If the removal causes no more references to a particular behavior to be in the dictionary, CompleteManipulation is called, which simply calls CompleteManipulation on the behavior’s manipulation engine, signaling it that the manipulation it was tracking is now complete.
Observant readers may have noticed that the method for associating behaviors and touches within the OnFrameReported handler means that the previous discussion treats multiple finger presses on a UIElement as a single unit – there is no support for Pinch and Rotate, which is being left as an exercise for another day…
Raising the Events
Once all of this plumbing is done, raising the events is simple enough – it is just a matter of subscribing to the manipulation engine’s events and echoing them to the behavior’s consumers. The manipulation engine events are hooked in the behavior instance’s constructor (the event declaration with the delegate {} assignment avoids all that nasty boilerplate check-for-null-when-firing-an-event code…)
Code Snippet
  1. public event EventHandler<Manipulation2DStartedEventArgs> ManipulationStarted = delegate { };
  2. public event EventHandler<Manipulation2DDeltaEventArgs> ManipulationDelta = delegate { };
  3. public event EventHandler<Manipulation2DCompletedEventArgs> ManipulationCompleted = delegate { };
Code Snippet
  1. /// <summary>
  2. /// Initializes a new instance of the <see cref=”Manipulate2DBehavior “/> class.
  3. /// </summary>
  4. public Manipulate2DBehavior()
  5. {
  6. _manipulationProcessor = new ManipulationProcessor2D(Manipulations2D.Translate);
  7. _manipulationProcessor.Started += (o, e) => ManipulationStarted(AssociatedObject, e);
  8. _manipulationProcessor.Delta += (o, e) => ManipulationDelta(AssociatedObject, e);
  9. _manipulationProcessor.Completed += OnManipulationCompleted;
  10. }
Hooking it All Up
To wire up the behavior, simply attach it to your desired UIElement and provide handlers for the events, as in the following code, adapted from Jeff’s articles…sorry, no animated penguins
Markup:
Code Snippet
  1. <navigation:Page x:Class=”Wintellect.Touch.MultiManipulatePage”
  2. xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;
  3. xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;
  4. xmlns:d=”http://schemas.microsoft.com/expression/blend/2008&#8243;
  5. xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006&#8243;
  6. xmlns:navigation=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation”
  7. xmlns:i=”clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity”
  8. xmlns:Touch=”clr-namespace:Wintellect.Touch;assembly=Wintellect.Touch”
  9. mc:Ignorable=”d” d:DesignWidth=”800″ d:DesignHeight=”600″
  10. Title=”MultiManipulatePage Page”>
  11. <Grid x:Name=”LayoutRoot” Background=”White”>
  12. <Rectangle x:Name=”RedRect” Width=”200″ Height=”200″ Fill=”Red”>
  13. <Rectangle.RenderTransform>
  14. <TranslateTransform Y=”-200″/>
  15. </Rectangle.RenderTransform>
  16. <i:Interaction.Behaviors>
  17. <Touch:Manipulate2DBehavior
  18. IsInertial=”True”
  19. ManipulationStarted=”TouchShapeBehavior_ManipulationStarted”
  20. ManipulationDelta=”TouchShapeBehavior_ManipulationDelta”
  21. ManipulationCompleted=”TouchShapeBehavior_ManipulationCompleted”/>
  22. </i:Interaction.Behaviors>
  23. </Rectangle>
  24. <Ellipse x:Name=”BlueCircle” Width=”200″ Height=”200″ Fill=”Blue”>
  25. <Ellipse.RenderTransform>
  26. <TranslateTransform Y=”200″ />
  27. </Ellipse.RenderTransform>
  28. <i:Interaction.Behaviors>
  29. <Touch:Manipulate2DBehavior
  30. IsInertial=”True”
  31. ManipulationStarted=”TouchShapeBehavior_ManipulationStarted”
  32. ManipulationDelta=”TouchShapeBehavior_ManipulationDelta”
  33. ManipulationCompleted=”TouchShapeBehavior_ManipulationCompleted”/>
  34. </i:Interaction.Behaviors>
  35. </Ellipse>
  36. </Grid>
  37. </navigation:Page>
Codebehind:
Code Snippet
  1. public partial class MultiManipulatePage : Page
  2. {
  3. public MultiManipulatePage()
  4. {
  5. InitializeComponent();
  6. }
  7. // Executes when the user navigates to this page.
  8. protected override void OnNavigatedTo(NavigationEventArgs e)
  9. {
  10. }
  11. private void TouchShapeBehavior_ManipulationStarted(Object sender, Manipulation2DStartedEventArgs e)
  12. {
  13. var senderShape = (Shape)sender;
  14. senderShape.Tag = senderShape.Fill;
  15. senderShape.Fill = new SolidColorBrush(Colors.Yellow);
  16. }
  17. private void TouchShapeBehavior_ManipulationDelta(Object sender, Manipulation2DDeltaEventArgs e)
  18. {
  19. var senderShape = (Shape)sender;
  20. var translateTransform = (TranslateTransform)senderShape.RenderTransform;
  21. translateTransform.X += e.Delta.TranslationX;
  22. translateTransform.Y += e.Delta.TranslationY;
  23. }
  24. private void TouchShapeBehavior_ManipulationCompleted(Object sender, Manipulation2DCompletedEventArgs e)
  25. {
  26. var senderShape = (Shape)sender;
  27. //TODO: This should really be done at the end of inertia, otherwise it will take the original color and keep moving…
  28. senderShape.Fill = senderShape.Tag as Brush;
  29. }
  30. }
That’s Interesting – Now What about the Phone?
What we have seen so far is the use of Behaviors and the Manipulations Assembly to provide manipulation event support in Silverlight 4 similar to that available in Windows Phone – in fact, better than that available in Windows Phone, since it can handle the simultaneous manipulation of multiple objects. But I said at the beginning that this could be extended to the phone – soooo…
It turns out this is quite simple to add to the phone. Because Windows Phone can consume regular Silverlight assemblies (as long as they do not stray outside of the phone’s own unique ‘sandbox’), the process is quite straightforward. Starting with a regular Silverlight for Windows Phone project, once again add references to System.Windows.Interactivity and to the Manipulations Assembly System.Windows.Input.Manipulations.dll. Then create the exact same Manipulate2DBehavior class in the phone project (there are techniques for sharing this code, including compiling it into its own assembly or using Add Existing as Link, for which information can be found elsewhere.) Using the same markup and codebehind content will provide similar results on the phone.
Markup:
Code Snippet
  1. <phone:PhoneApplicationPage
  2. x:Class=”MultiManipulate.Views.MultiManipulatePage”
  3. xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;
  4. xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;
  5. xmlns:phone=”clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone”
  6. xmlns:shell=”clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone”
  7. xmlns:d=”http://schemas.microsoft.com/expression/blend/2008&#8243;
  8. xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006&#8243; xmlns:i=”clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity” xmlns:Touch=”clr-namespace:Wintellect.Touch” FontFamily=”{StaticResource PhoneFontFamilyNormal}
  9. FontSize=”{StaticResource PhoneFontSizeNormal}
  10. Foreground=”{StaticResource PhoneForegroundBrush}
  11. SupportedOrientations=”Portrait” Orientation=”Portrait”
  12. mc:Ignorable=”d” d:DesignHeight=”768″ d:DesignWidth=”480″
  13. shell:SystemTray.IsVisible=”True”>
  14. <!–LayoutRoot is the root grid where all page content is placed–>
  15. <Grid x:Name=”LayoutRoot” Background=”Transparent”>
  16. <Grid.RowDefinitions>
  17. <RowDefinition Height=”Auto”/>
  18. <RowDefinition Height=”*”/>
  19. </Grid.RowDefinitions>
  20. <!–TitlePanel contains the name of the application and page title–>
  21. <StackPanel x:Name=”TitlePanel” Grid.Row=”0″ Margin=”12,17,0,28″>
  22. <TextBlock x:Name=”ApplicationTitle” Text=”MY APPLICATION” Style=”{StaticResource PhoneTextNormalStyle}“/>
  23. <TextBlock x:Name=”PageTitle” Text=”page name” Margin=”9,-7,0,0″ Style=”{StaticResource PhoneTextTitle1Style}“/>
  24. </StackPanel>
  25. <!–ContentPanel – place additional content here–>
  26. <Grid x:Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″>
  27. <Rectangle x:Name=”RedRect” Width=”100″ Height=”100″ Fill=”Red”>
  28. <Rectangle.RenderTransform>
  29. <TranslateTransform/>
  30. </Rectangle.RenderTransform>
  31. <i:Interaction.Behaviors>
  32. <Touch:Manipulate2DBehavior
  33. IsInertial=”True”
  34. ManipulationStarted=”TouchShapeBehavior_ManipulationStarted”
  35. ManipulationDelta=”TouchShapeBehavior_ManipulationDelta”
  36. ManipulationCompleted=”TouchShapeBehavior_ManipulationCompleted”/>
  37. </i:Interaction.Behaviors>
  38. </Rectangle>
  39. <Ellipse x:Name=”BlueRect” Width=”100″ Height=”100″ Fill=”Blue”>
  40. <Ellipse.RenderTransform>
  41. <TranslateTransform />
  42. </Ellipse.RenderTransform>
  43. <i:Interaction.Behaviors>
  44. <Touch:Manipulate2DBehavior
  45. IsInertial=”True”
  46. ManipulationStarted=”TouchShapeBehavior_ManipulationStarted”
  47. ManipulationDelta=”TouchShapeBehavior_ManipulationDelta”
  48. ManipulationCompleted=”TouchShapeBehavior_ManipulationCompleted”/>
  49. </i:Interaction.Behaviors>
  50. </Ellipse>
  51. </Grid>
  52. </Grid>
  53. </phone:PhoneApplicationPage>
Codebehind:
Code Snippet
  1. public partial class MultiManipulatePage : PhoneApplicationPage
  2. {
  3. public MultiManipulatePage()
  4. {
  5. InitializeComponent();
  6. }
  7. private void TouchShapeBehavior_ManipulationStarted(Object sender, Manipulation2DStartedEventArgs e)
  8. {
  9. var senderShape = (Shape)sender;
  10. senderShape.Tag = senderShape.Fill;
  11. senderShape.Fill = new SolidColorBrush(Colors.Yellow);
  12. }
  13. private void TouchShapeBehavior_ManipulationDelta(Object sender, Manipulation2DDeltaEventArgs e)
  14. {
  15. var senderShape = (Shape)sender;
  16. var translateTransform = (TranslateTransform)senderShape.RenderTransform;
  17. translateTransform.X += e.Delta.TranslationX;
  18. translateTransform.Y += e.Delta.TranslationY;
  19. }
  20. private void TouchShapeBehavior_ManipulationCompleted(Object sender, Manipulation2DCompletedEventArgs e)
  21. {
  22. var senderShape = (Shape)sender;
  23. //TODO: This should really be done at the end of inertia, otherwise it will take the original color and keep moving…
  24. senderShape.Fill = senderShape.Tag as Brush;
  25. }
  26. }
The Wintellect Silverlight Touch Library – aka LightTouch
Ultimately, the code referenced above has made its way into a larger library that provides additional Touch functionality beyond just attachable support for Manipulations, including support for Gestures, as well as enhancements that make it very easy to add touch support to scrollable controls like the ListBox.  For Manipulations, Inertia is also added to the mix.  This core manipulation Behavior is actually at the heart of each of these additional elements.  This project is being published up on CodePlex and can be accessed at http://lighttouch.codeplex.com.
Summary
Obviously, it is a little hard to see all this in action. To that end, if you have a multi-touch-enabled monitor, you can download  the project from CodePlex and try it out. While there was some tedious boilerplate code required to hook touch events up to the individual UIElements’ manipulation behaviors, what results in the end is a reusable behavior that can be easily reused throughout an application.
Author’s Note: Parts of the content prepared for this article were inspired by content from Jeff Prosise’s blog series on “Touch Interfaces for Windows Phone”, as well as Mike Taulty’sTouched” blog series.