My colleague Developer Evangelist, Sam Stokes, in California has written a compelling article on dragging items in Windows Phone.
But I have a problem with Sam’s approach
Maybe it’s because I have a problem with Sam – but probably not; he’s actually one of my top 90,000 people @ Microsoft. So, let’s talk about moving things in XAML!
Sam moves objects around by incrementing and decrementing an item’s top/left dependency property inside a Canvas.
Like this:
In the code above, Sam is using the ManipuationDelta event. This awesome event allows an individual UI element to track the movement of finger gestures on it. It simplifies the typical events that have to handle and track.
MSDN: The ManipulationDelta event occurs multiple times when the user drags fingers over the screen during a manipulation and again when inertia occurs. You can use the IsInertial property to check whether the event is occurring during inertia.
The element on with ManipulationDelta event occurs is not affected in any way when the event occurs. You must provide the logic to the element that is to be manipulated. The CumulativeManipulation and DeltaManipulation properties, which are of type ManipulationDelta, contain data about how the position of the manipulations change and interpreted as moving, resizing, or rotating an object. You apply that information to the element that is to be manipulated.
But there’s more to that code. Sam might be using the coolest event, but how is he relocating the ellipse? He’s incrementing and decrementing the Canvas.Top and Left dependency properties. When he does this, the ellipse appears to move and track the finger on the touch panel.
What’s the problem?
The problem is deep. And I have to start by saying that Sam’s approach is not necessarily wrong. There could be situations where position inside a canvas is the best choice. However, let’s talk about the downsides:
Canvas or Grid?
Changing the top/left of a child element will give the impression that it is moving. But inside a grid you need to change the margin. If you want to move two items you need to factor in the distance between them. What’s the problem? Well, should you use canvas or grid or something else? It simply means this approach is a potentially inconsistent approach.
Who’s your Neighbor
Changing the top/left of a child element will give the impression that it is moving. Any peer elements whose layout is bound to the location of the moving object must be redrawn with ever value change. What’s the problem? Well, do you really know every potentially related element? It simply means this approach is a potentially expensive approach.
GPU Acceleration
Transforms are a regimented approach to altering an element, even moving it. Hardware acceleration can be attached to consistent, regimented approaches. What’s the problem? How can the GPU understand why you are changing a dependency property’s value? It can’t. It simply means this approach cannot take advantage of GPU hardware acceleration.
Is there an alternative?
Yes. It’s TranslateTransform – a Silverlight class specifically designed to accommodate the task of moving objects from one position to another. (TranslateTransform is also part of WPF). And get this, even in the documentation dips into this discussion:
MSDN: The local 0,0 for an object can be offset on a Canvas using Canvas.Left and Canvas.Top, but this does not count as a transform; the object retains its own local 0,0 in this case for transform purposes.
A TranslateTransform is easy to use. A TranslateTransform has an X and Y property which correlate to the relative position to the element’s original layout location. As you would expect, negative numbers move it in a reverse direction.
Apply a TranslateTransform like this:
And implement it like this:
In the code above, I handle the ManipulationDelta event to track the touch gestures by the user. In the handler, I increment and decrement the X and Y values of the TranslateTransform – just like Sam. And just like Sam, my object tracks (or moves) with the user’s finger. But unlike Sam, my approach is hardware accelerated and a common, repeatable pattern.
Show me!
In the video above, I create a simple touch-enabled application. In no small part, the reason so little code is required is the wonderful data provided by the ManipulationDelta event (discussed earlier). Either way, I hope this lean sample helps you leverage touch in your applications.
Conclusion
Admittedly, I am sort of picking on my colleague to make a point. The reality is, Sam’s approach works. In fact, it is a very common approach to moving elements in a XAML environment, but there are downsides – do those downsides really matter? Maybe not enough for you to rewrite your application, but then again maybe so.
You’re the developer, you need to make the final call. Now you have a little more information. Informed decisions are usually better decisions. But I can’t tell you what is right for your application. What I can tell you is that TranslateTransform is easy to use, powerful, high performing, and a consistent approach. Other than that, it’s up to you.
Special acknowledgement to Sam Stokes for starting a great discussion.
Best of luck!