Building A Multi-Touch Photo Viewer Control

by Morten 17. January 2012 22:02

If you want to view an image on your Windows Phone app, or on your Windows 8 tablet, most people would probably expect to be able to use their fingers to pinch zoom and drag using the touch screen.

Since this is a common scenario, I want to create a simple reusable control that allows me to do this using very little xaml, along the lines of this:

<my:ImageViewer
    Thumbnail="http://url.com/to/my/thumbnail.jpg"
    Image="http://url.com/to/my/MyImage.jpg"  />

…where Thumbnail is a low resolution image that loads fast, while the full resolution Image is being downloaded.

If you just want to use this control and don’t want to learn how to create a custom control, skip to the bottom to download the source for both Windows Phone and Windows 8 Runtime.

First off, we’ll create a new Windows Phone Class Library project and name it “SharpGIS.Controls”. (or whatever you like)

image

Create a new folder “Themes”, add a new XAML resource file and name it “Generic.xaml”. Make sure the “build action” for this file is set to “ApplicationDefinition”.

We will want to define the default template in this file for our control (if you are used to making User Controls, this is essentially where the XAML for custom controls go instead).

In the xaml we will want two things: An image for displaying a fast-loading thumbnail at first, and a second image for displaying the high resolution image. Also we will use a Grid around them to group them together. Generic.xaml should look something like this:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SharpGIS.Controls">
    <Style TargetType="local:ImageViewer">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:ImageViewer">
                    <Grid x:Name="Root" Background="Transparent">
                        <Image x:Name="Thumbnail" Source="{TemplateBinding Thumbnail}" CacheMode="BitmapCache" />
                        <Image x:Name="Image" Source="{TemplateBinding Image}" CacheMode="BitmapCache" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Notice the “CacheMode” property. This is important to set, to get proper performance when zooming and panning the image. If you have a Windows Phone try the official Facebook app, open an image and you will see what I mean (if you worked on that app PLEASE fix this).

Next up is the actual code. Add a new class, and name it “ImageViewer”. Make it inherit from ‘Control’. Add a constructor and use the “DefaultStyleKey” to tell Silverlight that you have a template defined in Generic.xaml that it should use.

public class ImageViewer : Control
{
    public ImageViewer()
    {
        DefaultStyleKey = typeof(ImageViewer);
    }
}

Next we define the dependency properties for the two images that the template was binding to:

public ImageSource Image
{
    get { return (ImageSource)GetValue(ImageProperty); }
    set { SetValue(ImageProperty, value); }
}

public static readonly DependencyProperty ImageProperty =
    DependencyProperty.Register("Image", typeof(ImageSource), typeof(ImageViewer), null);

public ImageSource Thumbnail
{
    get { return (ImageSource)GetValue(ThumbnailProperty); }
    set { SetValue(ThumbnailProperty, value); }
}

public static readonly DependencyProperty ThumbnailProperty =
    DependencyProperty.Register("Thumbnail", typeof(ImageSource), typeof(ImageViewer), null);

We should now be able to use this control in a Windows Phone project. Add a new Windows Phone Appplication project to your solution, right-click the ‘references’ and select “add reference’. Pick the SharpGIS.Controls project.

You should now be able to use some XAML like this to display an image:

<my:ImageViewer
    xmlns:my="clr-namespace:SharpGIS.Controls;assembly=SharpGIS.Controls"
    Thumbnail="http://url.com/to/my/thumbnail.jpg"
    Image="http://url.com/to/my/image.jpg" />

That’s all fine, but you still can’t use any touch to zoom the image.

Go back to the code and override OnApplyTemplate(). This code executes when the template from Themes\Generic.xaml has been loaded, and it’s your chance to grab any reference to the elements in there and ‘do something’ with them. In user controls you would often set the event handlers directly in the xaml. With templates on custom controls, you will have to hook these up in code-behind during OnApplyTemplate().

Here we will hook up for the manipulation events, as well as assign a transform we will apply to the element when these events trigger.

private Grid Root;
        
public override void OnApplyTemplate()
{
    Root = GetTemplateChild("Root") as Grid;
    if (Root != null)
    {
        Root.ManipulationDelta += Root_ManipulationDelta;
        Root.ManipulationStarted += Root_ManipulationStarted;
        Root.RenderTransform = new CompositeTransform();
    }
    base.OnApplyTemplate();
}

The ManipulationDelta event triggers as you move. It will give you information about how much the user dragged, and how much he/she pinches, as well as the center of the pinch. Unfortunately the pinch scale amount is shown as separate X and Y directions, and no ‘Uniform Scale’ is shown. This makes it hard to get a good average of the scale, and you would have to pick just one of them (one could be pinching and the other stretching).

I’ve found that defining the amount you’re scaling is the change of the length of the diagonal of the boundingbox of all the touch points works well. Errrrrrr, that might have sounded confusing. Let’s use a picture instead. The orange circles below are touchpoints, and the rectangle is the box that encompasses all of them (2 or more points). The blue line is the diagonal length of this box. So the amount of scaling = length_Before / length_After.

image

We don’t get the actual touch points in the manipulation events. So instead I start with a simple box that I define as 1x1 and track the scaling of it. The diagonal length of that box at the beginning is the square root of 2, which we will define in the ManipulationStarted event. We also add a property for tracking the center of the box.

private Point? lastOrigin;
private double lastUniformScale;

private void Root_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
    lastUniformScale = Math.Sqrt(2);
    lastOrigin = null;
}

So all that’s left is listen to the ManipulationDelta event, and update the transform on the grid. This consist of comparing previous origin to the new, as well as calculating the scale factor based on the box diagonal. Also note that when you apply scale, this is means you’re scaling out and away from the upper left corner. To offset this, you will need to add some additional translation to the image, as shown below:

private void Root_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
    var transform = Root.RenderTransform as CompositeTransform;
    if (transform != null)
    {
        var origin = e.ManipulationContainer.TransformToVisual(this).Transform(e.ManipulationOrigin);

        if (!lastOrigin.HasValue)
            lastOrigin = origin;

        //Calculate uniform scale factor
        double uniformScale = Math.Sqrt(Math.Pow(e.CumulativeManipulation.Scale.X, 2) + 
                                        Math.Pow(e.CumulativeManipulation.Scale.Y, 2));
        if (uniformScale == 0)
            uniformScale = lastUniformScale;

        //Current scale factor
        double scale = uniformScale / lastUniformScale;

        if (scale > 0 && scale != 1)
        {
            //Apply scaling
            transform.ScaleY = transform.ScaleX *= scale;
            //Update the offset caused by this scaling
            var ul = Root.TransformToVisual(this).Transform(new Point());
            transform.TranslateX = origin.X - (origin.X - ul.X) * scale;
            transform.TranslateY = origin.Y - (origin.Y - ul.Y) * scale;
        }
        //Apply translate caused by drag
        transform.TranslateX += (origin.X - lastOrigin.Value.X);
        transform.TranslateY += (origin.Y - lastOrigin.Value.Y);

        //Cache values for next time
        lastOrigin = origin;
        lastUniformScale = uniformScale;
    }
}

And that’s it!

Now what’s left is to turn off the thumbnail when the image has loaded, as well as raise loaded events for the high resolution image, so that you can display a progress bar while you wait for the image to load. I won’t go into details on this, but in OnApplyTemplate, simply grab the Image template child, and listen for the ImageLoaded event.

I’ve packaged it all up in one complete control, as well as a sample showing how this would be used in an application where you would navigate to a page with this control on it.

You can download the source and a sample app here.

Here’s a preview off what that app looks like:

Tags:

Windows Phone | XAML

Comments (5) -

1/18/2012 8:49:29 AM

John Schroedl

Very cool!  

I haven't tackled phone dev yet so forgive my asking but is the phone ManipulationDeltaEvent different between WPF and the Phone?

In WPF, we have all the touch points in the manipulation event. Ex:

foreach (IManipulator m in deltaArgs.Manipulators) {
   Point tp = m.GetPosition(this);
}

Also, we avoid the Sqrt and Pow by using the precomputed length of the scale vector which WPF gives to us:

scale = deltaArgs.CumulativeManipulation.Scale.Length / 1.41;  // Normalize to [0..1]

Anyway, thanks for posting this. It's pretty cool!
John

John Schroedl United States

1/18/2012 10:02:21 AM

Morten

John: No the are pretty much the same as WPF, however WPF does give you more information as you point out (including the correct scaling that I would have to jimmy rig to get to on WP7).

Morten United States

3/18/2012 6:25:43 AM

Tareq

Hi, You said you have a windows 8 control (winrt). can you provide the link to that? thanks

Tareq U.A.E.

3/19/2012 7:33:53 AM

Morten

Tareq: I said that? When? I don't have a Win8 version at this point but you could probably fairly easy port the above code to WinRT.

Morten United States

3/21/2012 4:26:31 AM

Tareq

I read that "If you just want to use this control and don’t want to learn how to create a custom control, skip to the bottom to download the source for both Windows Phone and Windows 8 Runtime."

I thought you have it lol
btw thanks, it helped a lot in my windows phone app

Tareq U.A.E.

3/28/2012 6:16:28 PM

five finger shoes vibram

YC- Any training Vibram shoes gets stale after four to six weeks and michael kors watch stops working http://www.vibramfive-sales.com/. So whether you're looking to Vibram Bikila learn how to use kettle vibrams five fingers bells for the first time or if you're a seasoned vet and looking for a new michael kors mid-size mercer chronograph watch, golden challenge, kettle bell books, DVD's and five finger vibram bikila instructional courses are always a good bet. No amount of vibram fivefinger shoes for women instructional articles, videos, books, or DVD's can replace in-person instruction michael kors sale when it comes to kettle bell five fingers uk sale training. Look up your local RKC and purchase some vibram five fingers kso training sessions as a gift to get your kettle bell aficionado going on the right foot - or watches michael kors to perfect their technique. These vibram 5 fingers sale may look a little different and special but actually they are really quite cool and can be used for a five fingers shoes uk shop multitude of purposes http://www.michael-kors-sale.net/. Whether you just want something to walk around the home or to the speed shoes, perhaps you climb or do some light trekking or you may want the Vibram Five Fingers for running. There is vibram five finger toes very little padding on the shoes, as Vibram have designed them in a way that reflects the michael kors mens watches natural properties of feet; this means five fingers uk sale that there is very little interference from the shoes, which effectively mimic barefoot movement. http://www.vibram-five-finger.net/

five finger shoes vibram People's Republic of China

3/31/2012 7:43:23 PM

annora coast dress

LF- Barbour jackets are a clothing manufacturer originating from the north of coast clothing England; they have gained a solid http://www.uk-barbour-jacket.org/ reputation in the creation and manufacturing of barbour jacket women hardwearing, durable and fashionable coast irah red designed for outdoor use. The reason that they are so popular at present is largely due to the recent country/townie barbour quilted jacket fashions that are set to be big coast fashion news this season. As a hunting-type barbour quilted jacket ladies, the Barbour quilted jacket is perfect for adapting to recent coast victory dress styles. Founded in 1894, the company red barbour jacket has never been far from the minds of floral dresses fashion conscious individuals throughout the world. Often considered the sophisticated man's style of fashion, these coats form part of a classical style of womens barbour jackets dress. Renowned for their coast maxi dresses hardwearing, high-quality garments, Barbour really are head and shoulders above the rest. They are famous for providing clothing for many barbour shop of the country's high-flying elite; as such, they have a fantastic reputation, which is coast evening dresses uk much warranted. http://www.uk-womendresses.biz/

annora coast dress People's Republic of China

4/9/2012 7:29:11 AM

adfasdf

adfasdf

adfasdf United States

4/11/2012 11:11:17 PM

mialisa

In regard to the angle of the cloak-and-dagger art, <a href="www.michaelkorsfactory.net/michael-kors-hamilton-black-large-tote-p-461.html">michael kors hamilton black large tote</a> this article do not calculate too successful, but it of the experiment is however the far far larger than in meaning the success oneself. positive so-called:" a the horse dashes about, shooting the birds lead the bow, the world is all in my heart!" floor lord really not the is <a href="www.michaelkorsfactory.net/michael-kors-gia-black-satchel-p-475.html">michael kors gia black satchel</a> to has boundary new generation to open the mountain strange! i will have disappointed to this community originally, feeling that this community had no the prospect, the in the mind is filled with the woe.

mialisa United States

4/12/2012 2:53:44 AM

coast dresses

the most well-known brand-name one of the <A title="coast dresses" href="http://www.coast-dresses.info">coast dresses</A> have already broken down the market, to

distinguish the evening gown and day dress so that consumers can be more simple choice.

coast dresses United Kingdom

4/14/2012 1:02:41 AM

red bottom shoes

Miu Miu bags are young, refreshing, active yet with strong fashion force and gorgeous power in the fashion world, which just make them the favorite companion of modern fashion-conscious ladies! With classically brilliant design and ultra high-end quality, Miu Miu Bags are always there to stand the test of time! To own such adorable purses, come to visit Miu Miu outlet, where we get the fashion perfect Miu Miu bags to suit every ladies flavor. Multiple colors, designs and styles are available from Miu Miu sale online for you to choose from with quality guaranteed! http://www.miumiu-outlets.com/
Red Bottom shoes 2012 new season hot sale online at cheap price with free shipping to worldwide destinations. Step into high fashion territory with Christian Louboutin's signature red-soled styles! The iconic French footwear maverick relentlessly dreams up fabulous must-haves that dance daringly between the demure and the sensational. Choose Christian Louboutin sale shoes! Take a fashionable stance in his vertiginous cigarette stilettos, perpetually chic platform pumps and classically elegant clutches. Love Louboutin? Well, just choose your favorite from our Christian Louboutin Outlet online store that you will be always proud of your choice and be the stand out whenever you wear the shoes!  http://www.redbottomshoes-style.com
Famed with the brand’s iconic polo shirts, Polo Ralph Lauren offers a lasting menswear with a preppy attitude. The signature most popular Ralph Lauren Polo Shirts was introduced in 1972 in a superiorly and richly wide color collection, and instantly become a male wearing classic and favorite, which offers men’s modern leisure wear both essential style, premium quality and covetable variety! Till now, the classic polo shirts have build a brilliantly rich history of designs with awesome and elevated seasonal collections that always offer distinguished, effortless style for us to adore! Now with a full collection of Ralph Lauren men’s wearing, including polo shirts, casual favorite rugbys, sweatshirts, sweaters and down jackets offered, Ralph Lauren Sale makes all of your favorite items from winter jackets to summer polo shirts available to your fingertips, 55% off, free shipping offered, 24 hours online! http://www.poloralphlauren4sale.com/

red bottom shoes Sweden

4/25/2012 8:08:39 AM

asdfasdf

asdfasdf

asdfasdf United States

5/14/2012 1:04:03 AM

Bottom Shoes

One of the reasons why Mad Men has been such a successful show is that it harks back to a more glamorous time.Being stylish today means wearing sportswear and pyjama <a href="http://www.redbottomsoutlet.com Red bottoms</a>, so it's a tonic to see women with cinched waists and men in tailored suits.
January Jones' character Betty Draper has weathered many storms in the five seasons of the show, but she's waded through every emotional tsunami in her kitten <a href="http://www.redbottomsoutlet.com Red Bottom Heels</a>.And for the uninitiated, that's included being a mother to three children (one of dubious paternity) two unhappy marriages and most recently, debilitating seclusion on her second husband's Victorian estate.

Bottom Shoes People's Republic of China

5/28/2012 1:25:43 AM

business suits

I read that "If you just want to use this control and don’t want to learn how to create a custom control, skip to the bottom to download the source for both Windows Phone and Windows 8 Runtime."

business suits United States

5/28/2012 1:27:07 AM

business suits

what a superb sites

business suits United States

Pingbacks and trackbacks (5)+

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

About the author

Morten Nielsen

Silverlight MVP

Morten Nielsen
<--That's me
E-mail me Send mail

Twitter @dotMorten 

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2005-2011

Month List

RecentComments

Comment RSS