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日