WPF 实现图片在画布中缩放、拖动以及旋转

<uc:RulerCanvas x:Class="ShinePhoto.UC.ImageViewUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:uc="clr-namespace:ShinePhoto.UC" Width="1920" Height="1080"
             mc:Ignorable="d"  x:Name="canvas"
             d:DesignHeight="300" d:DesignWidth="30">
    <uc:RulerCanvas.Background>
        <ImageBrush ImageSource="/Images/ImageViewBG.png" />
    </uc:RulerCanvas.Background>
    <Button x:Name="CloseButton" Click="CloseButton_Click" Canvas.Right="10" Canvas.Top="10">
        <Image Source="pack://application:,,,/ShinePhoto.Icons;Component/flat/64/x.png" />
    </Button>
    <!--<Image x:Name="image" Width="200" IsManipulationEnabled="True" Source="/Images/flower.jpg" >
        <Image.RenderTransform>
            <MatrixTransform Matrix="1.5929750047527,0.585411309251951,-0.585411309251951,1.5929750047527,564.691807426081,79.4658072348299"/>
        </Image.RenderTransform>
    </Image>-->
    <!--<Image x:Name="image" Width="200" IsManipulationEnabled="True" Source="/Images/flower.jpg" >
            <Image.RenderTransform>
                <MatrixTransform Matrix="1.5929750047527,0.585411309251951,-0.585411309251951,1.5929750047527,564.691807426081,79.4658072348299"/>
            </Image.RenderTransform>
        </Image>
        <Image x:Name="image2" Width="200" IsManipulationEnabled="True" Source="/Images/flower2.jpg" >
            <Image.RenderTransform>
                <MatrixTransform  Matrix="1.79780224775912,-1.1136472330559,1.1136472330559,1.79780224775912,45.6962327448951,205.029554723656" />
            </Image.RenderTransform>
        </Image>
        <Image x:Name="image3" Width="200" IsManipulationEnabled="True" Source="/Images/flower3.jpg" >
            <Image.RenderTransform>
                <MatrixTransform Matrix="2.41806325085411,-0.0527474549128994,0.0527474549128994,2.41806325085411,280.737615796121,292.420001677231"/>
            </Image.RenderTransform>
        </Image>-->
</uc:RulerCanvas>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ShinePhoto.UC
{
    /// <summary>
    /// ImageViewUserControl.xaml 的交互逻辑
    /// </summary>
    public partial class ImageViewUserControl : RulerCanvas
    {
        public ImageViewUserControl()
        {
            InitializeComponent();
            this.Loaded += (sender, e) => {
                canvas.ManipulationStarting += new EventHandler<ManipulationStartingEventArgs>(image_ManipulationStarting);
                canvas.ManipulationDelta += new EventHandler<ManipulationDeltaEventArgs>(image_ManipulationDelta);
                // inertia
                canvas.ManipulationInertiaStarting += new EventHandler<ManipulationInertiaStartingEventArgs>(canvas_ManipulationInertiaStarting);
            };
        }
        void canvas_ManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
        {
            // Decrease the velocity of the Rectangle's movement by
            // 10 inches per second every second.
            // (10 inches * 96 DIPS per inch / 1000ms^2)
            e.TranslationBehavior = new InertiaTranslationBehavior()
            {
                InitialVelocity = e.InitialVelocities.LinearVelocity,
                DesiredDeceleration = 10.0 * 96.0 / (1000.0 * 1000.0)
            };
            // Decrease the velocity of the Rectangle's resizing by
            // 0.1 inches per second every second.
            // (0.1 inches * 96 DIPS per inch / (1000ms^2)
            e.ExpansionBehavior = new InertiaExpansionBehavior()
            {
                InitialVelocity = e.InitialVelocities.ExpansionVelocity,
                DesiredDeceleration = 0.1 * 96 / 1000.0 * 1000.0
            };
            // Decrease the velocity of the Rectangle's rotation rate by
            // 2 rotations per second every second.
            // (2 * 360 degrees / (1000ms^2)
            e.RotationBehavior = new InertiaRotationBehavior()
            {
                InitialVelocity = e.InitialVelocities.AngularVelocity,
                DesiredDeceleration = 720 / (1000.0 * 1000.0)
            };
            e.Handled = true;
        }
        UIElement last;
        void image_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
        {
            // lazy hack not in the blog post..
            var uie = e.OriginalSource as UIElement;
            if (uie != null)
            {
                if (last != null) Canvas.SetZIndex(last, 0);
                Canvas.SetZIndex(uie, 2);
                last = uie;
            }
            //canvas is the parent of the image starting the manipulation;
            //Container does not have to be parent, but that is the most common scenario
            e.ManipulationContainer = canvas;
            e.Handled = true;
            // you could set the mode here too
            // e.Mode = ManipulationModes.All;            
        }
        void image_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            //this just gets the source.
            // I cast it to FE because I wanted to use ActualWidth for Center. You could try RenderSize as alternate
            var element = e.Source as FrameworkElement;
            if (element != null)
            {
                //e.DeltaManipulation has the changes
                // Scale is a delta multiplier; 1.0 is last size,  (so 1.1 == scale 10%, 0.8 = shrink 20%)
                // Rotate = Rotation, in degrees
                // Pan = Translation, == Translate offset, in Device Independent Pixels
                var deltaManipulation = e.DeltaManipulation;
                var matrix = ((MatrixTransform)element.RenderTransform).Matrix;
                // find the old center; arguaby this could be cached
                Point center = new Point(element.ActualWidth / 2, element.ActualHeight / 2);
                // transform it to take into account transforms from previous manipulations
                center = matrix.Transform(center);
                //this will be a Zoom.
                matrix.ScaleAt(deltaManipulation.Scale.X, deltaManipulation.Scale.Y, center.X, center.Y);
                // Rotation
                matrix.RotateAt(e.DeltaManipulation.Rotation, center.X, center.Y);
                //Translation (pan)
                matrix.Translate(e.DeltaManipulation.Translation.X, e.DeltaManipulation.Translation.Y);
                ((MatrixTransform)element.RenderTransform).Matrix = matrix;
                e.Handled = true;
                // We are only checking boundaries during inertia
                // in real world, we would check all the time
                if (e.IsInertial)
                {
                    Rect containingRect = new Rect(((FrameworkElement)e.ManipulationContainer).RenderSize);
                    Rect shapeBounds = element.RenderTransform.TransformBounds(new Rect(element.RenderSize));
                    // Check if the element is completely in the window.
                    // If it is not and intertia is occuring, stop the manipulation.
                    if (e.IsInertial && !containingRect.Contains(shapeBounds))
                    {
                        //Report that we have gone over our boundary
                        e.ReportBoundaryFeedback(e.DeltaManipulation);
                        // comment out this line to see the Window 'shake' or 'bounce'
                        // similar to Win32 Windows when they reach a boundary; this comes for free in .NET 4               
                        e.Complete();
                    }
                }
            }
        }
        private void CloseButton_Click(object sender, RoutedEventArgs e)
        {
            this.Visibility = System.Windows.Visibility.Collapsed;
        }
        /* void rect_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            TransformGroup tg = rect.RenderTransform as TransformGroup ;
            if (e.DeltaManipulation.Translation != null)
            {
                   
                var trans = tg.Children[0] as TranslateTransform;
                trans.X += e.DeltaManipulation.Translation.X;
                trans.Y += e.DeltaManipulation.Translation.Y;
            }
            if (e.DeltaManipulation.Scale != null)
            {
                var scale = tg.Children[1] as ScaleTransform;
                scale.ScaleX *= e.DeltaManipulation.Scale.X;
                scale.ScaleY *= e.DeltaManipulation.Scale.Y;
                scale.CenterX = 0.5;
                scale.CenterY = 0.5;
                Point origin = e.ManipulationOrigin;
            }
            e.Handled = true;
        }*/
    }
}


知识共享许可协议
《WPF 实现图片在画布中缩放、拖动以及旋转》常伟华 创作。
采用 知识共享 署名-相同方式共享 3.0 中国大陆 许可协议进行许可。
  • 多说评论
  • 签名
  • 新浪微博
  • 默认评论
  • Tab Header 5

0 条评论 / 点击此处发表评论

Tab Content 5

开发技术


开发平台和工具

sitemap     148.06ms