Posts Tagged ‘Pinch’

Smooth flick and zoom with Viewport control for Windows Phone

April 8, 2014 7 comments

One of best features of Windows Phone is its fluid way for flick and zoom of images in your photo albums. Yet, most of apps that show images aren’t implemented that way of handling images (e.g. Facebook, Twitter, WhatsApp, etc.) and flicking images is pretty laggy in my opinion (actually it just a pan). However, there is simple solution for such cases and it is called Viewport control.

Essentially, Viewport control for Windows Phone handles pan and flick gestures of its content and provides smooth bounce effect when you flick content (image, canvas, etc.) that is larger than size of screen or viewport itself. You can see that effect in photo album or in Internet Explorer.

Implementation is very simple: just add Viewport control to page, put Image inside it and set Viewport Bound property to size of the image.

<Grid x:Name="LayoutRoot" Background="White">
    <ViewportControl Bounds="0,0,1249,1920">
        <Image Source="/Assets/Saga_14.jpg" />

And that is it. See how it looks:


In order to implement zoom we have to manualy resize image and set view point in ManipulationDelta event of Viewport control. Set XAML code in this way:

<Grid x:Name="LayoutRoot" Background="White">
    <ViewportControl x:Name="viewport" 
        ManipulationCompleted="viewport_ManipulationCompleted" >
        <Image x:Name="image" Source="/Assets/Saga_14.jpg" 
               CacheMode="BitmapCache" Loaded="image_Loaded" 
               Stretch="None" Source="/Assets/Saga_14.jpg" />

In ManipulationDelta event we check for Pinch event (e.PinchManipulation != null) and use e.PinchManipulation.CumulativeScale value to calculate new size of image. Also we use e.PinchManipulation.Original.Center value to calculate new point of view for image, sice we want to zoom in and out at that place that pinch actualy occured on screen. To do that we have to do several things:

  • Get offset of image in viewport (or how much is image moved in viewport using transform.Matrix.OffsetX and transform.Matrix.OffsetY values):

     MatrixTransform transform = image.TransformToVisual(viewport) as MatrixTransform;

  • Calculate center of pinch gesture on image (not screen):

     Point pinchCenterOnImage = transform.Transform(e.PinchManipulation.Original.Center);

  • Calculate and set new origin point of viewport:

     Point newOriginPoint = new Point(relativeCenter.X * newWidth – pinchCenterOnImage.X, relativeCenter.Y * newHieght – pinchCenterOnImage.Y);


Complete code behind in ManipulationDelta event looks like:

private double m_Zoom = 1;
private double m_Width = 0;
private double m_Height = 0;

private void viewport_ManipulationDelta(object sender, 
System.Windows.Input.ManipulationDeltaEventArgs e)
    if (e.PinchManipulation != null)

        double newWidth, newHieght;

        if (m_Width < m_Height)  // box new size between image and viewport
            newHieght = m_Height * m_Zoom * e.PinchManipulation.CumulativeScale;
            newHieght = Math.Max(viewport.ActualHeight, newHieght);
            newHieght = Math.Min(newHieght, m_Height);
            newWidth = newHieght * m_Width / m_Height;
            newWidth = m_Width * m_Zoom * e.PinchManipulation.CumulativeScale;
            newWidth = Math.Max(viewport.ActualWidth, newWidth);
            newWidth = Math.Min(newWidth, m_Width);
            newHieght = newWidth * m_Height / m_Width;

        if (newWidth < m_Width && newHieght < m_Height)
            MatrixTransform transform = image.TransformToVisual(viewport) 
              as MatrixTransform;
            Point pinchCenterOnImage = 
            Point relativeCenter = 
              new Point(e.PinchManipulation.Original.Center.X / image.Width, 
              e.PinchManipulation.Original.Center.Y / image.Height);
            Point newOriginPoint = new Point(
              relativeCenter.X * newWidth - pinchCenterOnImage.X, 
              relativeCenter.Y * newHieght - pinchCenterOnImage.Y);

        image.Width = newWidth;
        image.Height = newHieght;

        // Set new view port bound
        viewport.Bounds = new Rect(0, 0, newWidth, newHieght);

private void viewport_ManipulationCompleted(object sender, 
System.Windows.Input.ManipulationCompletedEventArgs e)
    m_Zoom = image.Width / m_Width;


Here is zoom in action


You can download sample code on

Categories: Windows Phone Tags: , , , , ,