There are already a lot of useful WPF UI controls that, with a few easy adjustments, can be used within a Surface application. Basically you only need to adjust mouse events to contact events.
In this blog post I cover how you can make 2 controls Surface ready, provide a quick walkthrough and the resulting code.
First is the WPF Book control from Mitsu Furuta that is available at Codeplex (http://www.codeplex.com/wpfbookcontrol) and is described in a blog post at http://blogs.msdn.com/mitsu/archive/2007/04/18/wpf-book-control.aspx .
The second are the 3D tools found under http://3dtools.codeplex.com/ .
WPF Book Control
To port the book control I used the Project WPFMitsuControls and renamed it to SFMitsuControl.
First thing to do is to add the necessary references Microsoft.Surface and Microsoft.Surface.Presentation.
The book is based on a WPF ItemsControl and the pages are WPF ContentControl’s. To make them Surface enabled we need to change them to the corresponding Surface controls. After importing the namespace with xmlns:s=”http://schemas.microsoft.com/surface/2008″, we make the following changes:
<ItemsControl will be changed into <s:SurfaceItemsControl and
<ContentControl will be changed to <s:SurfaceContentControl
Don’t forget to change the code behind in Book.cs and BookPage.cs to inherit from the corresponding base classes.
This enables us to the ContactDown, ContactChanged and ContactUp events that we will use to replace the corresponding mouse events of the BookPage. We also need to change the MouseDown on the BookPages inside the book control. And that’s it! The code is pretty much the same as with the mouse events. You only need to make small adjustments like capturing the contact instead of the mouse.
The resulting code can be downloaded here: Surface Book Control
I took the demo app as is and only made a surface window and changed the UserControl to SurfaceUserControl. I did not bother to make the Usercontrols completely Surface enabled.
The second thing I cover are the 3D Tools. I will go over updating the trackball and Trackport3D.
We could just do the same with the trackball that we already did with the book control, but there is one thing that would be bothering. The trackball is moved with the left mouse button and zooming is done with the right mouse button. Of course we can’t zoom like this on a Surface. We don’t have a right button and on top of that it would be totally not cool! We will use multitouch zoom to accomplish this.
Luckily, MS gave as the ManipulationProcessor class that will greatly reduce the effort to interpret touch gestures.
Again, we start by adding the references Microsoft.Surface and Microsoft.Surface.Presentation.
The first control we change will be the Trackball. We need to add a local variable for our manipulation processor:
private Affine2DManipulationProcessor manipulationProcessor;
And then change the initialization of the events and init the processor when the EventSource Property gets updated.
this.manipulationProcessor = new Affine2DManipulationProcessor(
manipulationProcessor.Affine2DManipulationDelta += new EventHandler<Affine2DOperationDeltaEventArgs>(manipulationProcessor_Affine2DManipulationDelta);
input.PreviewContactDown += new ContactEventHandler(input_PreviewContactDown);
input.PreviewContactUp += new ContactEventHandler(input_PreviewContactUp);
This creates a new manipulation processor that allows us to translate and scale. We hook up to the Affine2DManipulationDelta event that tells us the scale and translate deltas that we will use to update our transform object.
We also hook up to the ContactDown and ContactUp events. When a contact is recognized in the ContactDown event handler, we capture it and tell our manipulation processor to track the contact. From now on, any change to the contact will go through our processor, and results in a delta in scale or translation. The processor does all the hard work here and we only need to look at the deltas, to see our change. The delta event handler looks like this now:
if (e.ScaleDelta != 0.0)
_previousPosition2D.X = e.ManipulationOrigin.X – e.Delta.X;
_previousPosition2D.Y = e.ManipulationOrigin.Y – e.Delta.Y;
_previousPosition3D = ProjectToTrackball(EventSource.ActualWidth, EventSource.ActualHeight, _previousPosition2D);
It’s pretty simple and just reuses the Track and Zoom function we already have.
We also need to update our Trackport3D UserControl to a SurfaceUserControl. And we need to change how the Trackport3D uses the trackball. The old one used a border control to capture the mouse events. Since we need a contact enabled control to capture the events, we will use a SurfaceContentControl to achieve this.
And that’s it for the trackball control. The resulting code can be found here: Surface 3D Tools
As you can see, it’s very easy to build upon available WPF controls for your Surface application. The changes are straight forward and the ManipulationProcessor gives you a great way to easily implement touch gestures.