WPF中文网

TransformGroup与图片查看器

TransformGroup同样继承于Transform,但是它多了一个TransformCollection类型的Children属性,表示可以将多个Transform组合成一个复合转换。复合转换就是将旋转、平移、缩放、倾斜合并起来形成一个集团转换。由于Children是一个集合,所以可以叠加多个不同的转换。

public sealed class TransformGroup : Transform
{
    public static readonly DependencyProperty ChildrenProperty;

    public TransformGroup();

    public TransformCollection Children { get; set; }
    public override Matrix Value { get; }

    public TransformGroup Clone();
    public TransformGroup CloneCurrentValue();

}

下面我们用一个示例演示TransformGroup的用法,开发一款图片查看器demo,在查看图片的时候,可以移动和缩放图片。移动图片需要用到TranslateTransform平移对象,缩放图片需要用到ScaleTransform缩放对象,将两个对象放到TransformGroup的Children属性中,最后将TransformGroup 作用到Image控件上即可。

下一步就是在鼠标的操作下,根据当前鼠标坐标位置,不断计算平移位置和缩放倍数,并修改TranslateTransform和ScaleTransform的相关属性,即可完成图片查看器的基本功能。

首先准备一张图片,将图片以Resource资源导入到项目中。

然后是XAML前端代码的编写。

<Window x:Class="HelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:HelloWorld" 
        xmlns:controls="clr-namespace:HelloWorld.Controls"
        xmlns:helper="clr-namespace:HelloWorld.MVVM"
        mc:Ignorable="d" Background="Black"  
        Title="WPF中文网 - www.wpfsoft.com" Height="350" Width="500">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <Canvas x:Name="canvas" Background="Transparent"
                MouseWheel="canvas_MouseWheel"
                MouseMove="canvas_MouseMove"
                MouseLeftButtonUp="canvas_MouseLeftButtonUp"
                MouseLeftButtonDown="canvas_MouseLeftButtonDown">
            <Image x:Name="image" Source="/Images/lyf.png"/>
        </Canvas>
        <TextBlock HorizontalAlignment="Left" 
                   VerticalAlignment="Bottom" 
                   Margin="15" Foreground="Red">
            <Run Text="X:"/>
            <Run Text="{Binding X}"/>
            <Run Text="Y:"/>
            <Run Text="{Binding Y}"/>
            <Run Text="Delta:"/>
            <Run Text="{Binding D}"/>
        </TextBlock>
    </Grid>
</Window>

重庆教主友情提示

注意,Canvas一定要设置背景颜色哦!不然捕捉不到鼠标事件。

在上面的代码中,我们实例化了一个Canvas对象用来接收鼠标的操作事件,并在里面实例化了一个Image控件,TextBlock 控件用来显示鼠标的坐标。

后端代码

using HelloWorld.Controls;
using HelloWorld.MVVM;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 HelloWorld
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private MainViewModel vm;
        private bool isMouseDown = false;
        private Point mousePoint = new Point(0,0);
        private TranslateTransform translateTransform = new TranslateTransform();
        private ScaleTransform scaleTransform = new ScaleTransform();
        private TransformGroup group = new TransformGroup();
        public MainWindow()
        {
            InitializeComponent();

            Loaded += (s, e) =>
            {
                vm = DataContext as MainViewModel;
                group.Children.Add(scaleTransform);
                group.Children.Add(translateTransform);
                image.RenderTransform = group;
                var scale = Math.Min(
                    canvas.ActualWidth / image.ActualWidth, 
                    canvas.ActualHeight / image.ActualHeight);
                scaleTransform.ScaleX = scale;
                scaleTransform.ScaleY = scale;
                translateTransform.X = (canvas.ActualWidth - image.ActualWidth * scale) / 2;
            };
        }



        private void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            isMouseDown = true;
            mousePoint = e.GetPosition(canvas);
        }

        private void canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            isMouseDown = false;
        }

        private void canvas_MouseMove(object sender, MouseEventArgs e)
        {
            var position = e.GetPosition(canvas);
            vm.X = position.X;
            vm.Y = position.Y;
            if (isMouseDown)
            {
                translateTransform.X += position.X - mousePoint.X;
                translateTransform.Y += position.Y - mousePoint.Y;
                mousePoint = position;
            }
        }

        private void canvas_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            var delta = e.Delta;
            double scale = delta * 0.001;
            var position = e.GetPosition(canvas);
            vm.X = position.X;
            vm.Y = position.Y;
            vm.D = delta;

            if (scaleTransform.ScaleX + scale < 0.1) return;

            Point inversePoint = group.Inverse.Transform(position);
            scaleTransform.ScaleX += scale;
            scaleTransform.ScaleY += scale;            
            translateTransform.X = -(inversePoint.X * scaleTransform.ScaleX - position.X);
            translateTransform.Y = -(inversePoint.Y * scaleTransform.ScaleY - position.Y);
        }
    }
}

第一步,定义TransformGroup 、ScaleTransform 和TranslateTransform 对象。

第二步,在初始化界面时,计算原始的图片放大倍率和平移位置。

第三步,在鼠标按下时设置标志位,鼠标移动时设置平移参数,鼠标滚动时计算缩放和平移,鼠标抬起时结束操作。

需要注意的是,进行缩放时需要拿到TransformGroup 的反函数并转换当前鼠标坐标,最后缩放结束后再设置平移位置,并再次取反。这样才能实现以鼠标坐标为中心对图片进行缩放。

当前课程源码下载:(注明:本站所有源代码请按标题搜索)

文件名:093-《TransformGroup复合转换》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff

——重庆教主 2023年11月3日

copyright @重庆教主 WPF中文网 联系站长:(QQ)23611316 (微信)movieclip (QQ群).NET小白课堂:864486030 | 本文由WPF中文网原创发布,谢绝转载 渝ICP备2023009518号-1