#743 – Using Touch Manipulation Events to Scale an Element

In the previous post, we used a ManipulationDelta object in the ManipulationDelta event handler to both translate and rotate a user interface element.  The user’s touch gestures for translation (sliding finger) and rotation (rotating two fingers) were automatically captured and available in the Translation and Rotation properties of the ManipulationDelta object.

We can also support scaling of an element using the ManipulationDelta event.  The ManipulationDelta object also contains a Scale property, which stores a Vector that indicates the target scale for the object (e.g. scale of 0.5 indicates 1/2 size).  This property is automatically set when a user uses two fingers on an element in a pinch or spread gesture, indicating that they want to zoom in or out of the element.

The sample code below supports all translation, rotation and scaling of an Image element.

    <Canvas Name="canvMain" Background="Transparent">
        <Image Source="JamesII.jpg" Width="100"
               RenderTransform="{Binding ImageTransform}"
               ManipulationStarting="Image_ManipulationStarting" ManipulationDelta="Image_ManipulationDelta"/>

Below is the code-behind for this sample.  Note that we now apply translation, rotation and scaling to the underlying matrix.

    public partial class MainWindow : Window, INotifyPropertyChanged
        public MainWindow()
            this.DataContext = this;

            ImageTransform = new MatrixTransform();

        private MatrixTransform imageTransform;
        public MatrixTransform ImageTransform
            get { return imageTransform; }
                if (value != imageTransform)
                    imageTransform = value;

        private void Image_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
            // Ask for manipulations to be reported relative to the canvas
            e.ManipulationContainer = canvMain;

        private void Image_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
            ManipulationDelta md = e.DeltaManipulation;
            Vector trans = md.Translation;
            double rotate = md.Rotation;
            Vector scale = md.Scale;

            Matrix m = imageTransform.Matrix;

            // Find center of element and then transform to get current location of center
            FrameworkElement fe = e.Source as FrameworkElement;
            Point center = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2);
            center = m.Transform(center);

            // Update matrix to reflect translation/rotation
            m.Translate(trans.X, trans.Y);
            m.RotateAt(rotate, center.X, center.Y);
            m.ScaleAt(scale.X, scale.Y, center.X, center.Y);

            imageTransform.Matrix = m;

            e.Handled = true;

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string prop)
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));