在WPF框架中有一个抽象类叫Transform,它定义了实现二维平面中的转换的功能。它包括旋转 (RotateTransform)、缩放 (ScaleTransform)、倾斜 (SkewTransform) 和平移 (TranslateTransform)4个子类。它定义如何将点从一个坐标空间映射或转换到另一个坐标空间。 此映射由转换 Matrix 来描述,它是一个三行三列 Double 值的集合。
这个类可以实现控件的各种转换,比如放置、缩放、倾斜和平移。
首先我们来看一下Transform的定义:
public abstract class Transform : GeneralTransform, IResource
{
public static Transform Identity { get; }
public abstract Matrix Value { get; }
public override GeneralTransform Inverse { get; }
public static Transform Parse(string source);
public Transform Clone();
public Transform CloneCurrentValue();
public override Rect TransformBounds(Rect rect);
public override bool TryTransform(Point inPoint, out Point result);
}
Identity表示获取一个Transform 标识转换,Value表示当前的Matrix矩阵变换,Inverse表示获取当前转换的反函数,它的类型是GeneralTransform。
对于任何Transform对象,一旦使用它去变换某个元素后,它的Inverse属性就会有值。它是GeneralTransform类型,也就是一个变换器,用于将元素变换到原始状态,相当于是Transform的反向操作。需要注意的是,Inverse是用于返回到原始状态的,而不上一次转换的状态。
以下内容来自官网的解释:
通过操作矩阵值,可以旋转、缩放、倾斜和移动(转换)对象。 例如,如果将第三行第一列的值(OffsetX 值)更改为 100,可使用它来将对象沿 x 轴移动 100 个单位。 如果将第二行第二列中的值更改为 3,可使用它来将对象的当前高度拉伸三倍。 如果同时更改这两个值,将使对象沿 x 轴移动 100 个单位,并将其高度拉伸 3 倍。 由于WPF仅支持仿射转换,因此右边列中的值始终为 0, 0, 1。
由于直接操作矩阵去设置旋转、缩放、倾斜和移动功能比较复杂,所以WPF提供了4个子类来设置相应的功能。例如,借助 ScaleTransform 类,通过设置其 ScaleX 和 ScaleY 属性即可缩放对象,而无需操作转换矩阵。 同样,借助 RotateTransform 类,只需设置其 Angle 属性,即可旋转对象。
下表中展示了2D转换
子类 | 说明 | 效果 | 备注 |
RotateTransform | 按指定的 Angle 旋转元素。 | 表示旋转一个对象的角度 | |
ScaleTransform | 按指定的 ScaleX 和 ScaleY 量缩放元素。 | 表示放大或缩小一个对象 | |
SkewTransform | 按指定的 AngleX 和 AngleY 量倾斜元素。 | 表示倾斜一个对象 | |
TranslateTransform | 按指定的 X 和 Y 量移动(转换)元素。 | 表示移动一个对象 | |
TransformGroup | 将多个 TransformGroup 对象组合成单个 Transform,然后你可以应用它来转换属性。 | ||
MatrixTransform | 建其他 Transform 类不提供的自定义转换。 使用 MatrixTransform 时,可直接操作矩阵。 |
转换和坐标系
转换对象时,不只是转换对象,还会转换该对象所在的坐标空间。 默认情况下,转换基于目标对象坐标系的原点 (0,0) 居中。 唯一例外是 TranslateTransform;由于其转换效果无论基于何处居中都相同,因此 TranslateTransform 没有可设置的中心属性。
以下示例使用 RotateTransform 围绕默认中心点 (0, 0) 将 Rectangle 元素(一种 FrameworkElement)旋转 45 度。 下图显示了旋转效果。
围绕点 (0,0) 旋转 45 度的矩形元素
<Canvas Width="200" Height="200">
<Rectangle
Canvas.Left="100" Canvas.Top="100"
Width="50" Height="50"
Fill="RoyalBlue" Opacity="1.0">
<Rectangle.RenderTransform>
<RotateTransform Angle="45" />
</Rectangle.RenderTransform>
</Rectangle>
</Canvas>
默认情况下,元素会围绕其左上角 (0, 0) 旋转。 RotateTransform、ScaleTransform 和 SkewTransform 类提供 CenterX 和 CenterY 属性,以便可以指定应用转换的点。
下面的示例也使用 RotateTransform 将 Rectangle 元素旋转 45 度;但是,这次对 CenterX 和 CenterY 属性进行了设置,使得 RotateTransform 以 (25, 25) 为中心。 下图显示了旋转效果。
围绕点 (25, 25) 旋转 45 度矩形元素
<Canvas Width="200" Height="200">
<Rectangle
Canvas.Left="100" Canvas.Top="100"
Width="50" Height="50"
Fill="RoyalBlue" Opacity="1.0">
<Rectangle.RenderTransform>
<RotateTransform Angle="45" CenterX="25" CenterY="25" />
</Rectangle.RenderTransform>
</Rectangle>
</Canvas>
FrameworkElement转换
FrameworkElement定义了两个有关转换的属性,分别是LayoutTransform和RenderTransform,前者在布局步骤前应用的转换,后者在布局步骤完成后应用,官方推荐使用RenderTransform,原因是可获得性能优势。另外,因为它们继承自 Animatable 类,所以 Transform 类可以被制作成动画。 若要对 Transform 进行动画处理,请将兼容类型的动画应用到要进行动画处理的属性。关于动画,我们会在下一章进行讲解。
下一节,我们将依次演示WPF的转换功能。
——重庆教主 2023年11月2日
RotateTransform表示旋转一个对象的角度。首先我们来看一下它的定义:
public sealed class RotateTransform : Transform
{
public static readonly DependencyProperty AngleProperty;
public static readonly DependencyProperty CenterXProperty;
public static readonly DependencyProperty CenterYProperty;
public RotateTransform();
public RotateTransform(double angle);
public RotateTransform(double angle, double centerX, double centerY);
public double Angle { get; set; }
public double CenterX { get; set; }
public double CenterY { get; set; }
public override Matrix Value { get; }
public RotateTransform Clone();
public RotateTransform CloneCurrentValue();
protected override Freezable CreateInstanceCore();
}
Angle属性表示获取或设置顺时针旋转的角度(以度为单位)。默认值是0度。CenterX 和CenterY 表示获取或设置旋转中心点的 x y坐标,Value属性表示当前转换的矩阵。通常我们只需要设置Angle、CenterX 和CenterY即可。
一、RotateTransform示例
前端代码
<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="Lavender"
MouseMove="Window_MouseMove"
Title="WPF中文网 - www.wpfsoft.com" Height="350" Width="500">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Width="100"
Height="25"
Content="RotateTransform"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Button.RenderTransform>
<RotateTransform Angle="{Binding ElementName=slider,Path=Value}"/>
</Button.RenderTransform>
</Button>
<Button Grid.Column="1"
Width="100"
Height="25"
Content="RotateTransform"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Button.RenderTransform>
<RotateTransform Angle="{Binding ElementName=slider,Path=Value}"
CenterX="50" CenterY="12.5"/>
</Button.RenderTransform>
</Button>
<Button x:Name="button"
Grid.Column="2"
Width="100"
Height="25"
Content="RotateTransform"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Button.RenderTransform>
<RotateTransform Angle="45"/>
</Button.RenderTransform>
</Button>
<Slider x:Name="slider"
Grid.ColumnSpan="3"
Margin="30"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Value="0"
Maximum="720"
Width="400" />
</Grid>
</Window>
在上面的代码中,我们分别用了3个按钮,每个按钮的RenderTransform属性都实例化了一个RotateTransform旋转类型,第一个RotateTransform只设置了Angle度,表示以对象左上角为轴圆心旋转,第二个RotateTransform 同时设置了Angle度、CenterX和CenterY设置为按钮尺寸的一半,表示以对象中间为轴圆心旋转,第三个RotateTransform 的实现比较有趣,我们先是初始化旋转角度为45度,在鼠标移动时,将鼠标的XY坐标相加并实时赋值给Angle属性,所以它看起来是跟随鼠标移动而旋转。
然后我们在C#后端写如下的代码:
private void Window_MouseMove(object sender, MouseEventArgs e)
{
if (button.RenderTransform is RotateTransform rotateTransform)
{
Point point = e.GetPosition(this);
rotateTransform.Angle = point.X + point.Y;
}
}
另外,这些Angle值的设置都是通过slider绑定的。最后,它们会呈现如下的样子:
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:089-《RotateTransform旋转转换》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年11月02日
ScaleTransform表示在二维xy坐标系内缩放对象。所以它放大缩小的方向只有两个,分别是X方向和Y方向。另外,每个方向上需要设置一个中心点。
public sealed class ScaleTransform : Transform
{
public static readonly DependencyProperty ScaleXProperty;
public static readonly DependencyProperty ScaleYProperty;
public static readonly DependencyProperty CenterXProperty;
public static readonly DependencyProperty CenterYProperty;
public ScaleTransform();
public ScaleTransform(double scaleX, double scaleY);
public ScaleTransform(double scaleX, double scaleY, double centerX, double centerY);
public double ScaleX { get; set; }
public double ScaleY { get; set; }
public double CenterX { get; set; }
public double CenterY { get; set; }
public override Matrix Value { get; }
public ScaleTransform Clone();
public ScaleTransform CloneCurrentValue();
protected override Freezable CreateInstanceCore();
}ScaleX
ScaleX属性:获取或设置X轴缩放比例。
ScaleY属性:获取或设置Y轴缩放比例。
CenterX属性:获取或设置当前缩放对象的X轴的中心坐标。
CenterY属性:获取或设置当前缩放对象的Y轴的中心坐标。
一、ScaleTransform示例
前端代码
<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="Lavender"
MouseMove="Window_MouseMove"
Title="WPF中文网 - www.wpfsoft.com" Height="350" Width="500">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Width="100"
Height="25"
Content="ScaleTransform"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Button.RenderTransform>
<ScaleTransform ScaleX="{Binding ElementName=sliderX,Path=Value}"
ScaleY="{Binding ElementName=sliderY,Path=Value}"/>
</Button.RenderTransform>
</Button>
<Button x:Name="button"
Grid.Column="1"
Width="100"
Height="25"
Content="ScaleTransform"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Button.RenderTransform>
<ScaleTransform CenterX="50" CenterY="12.5"/>
</Button.RenderTransform>
</Button>
<Slider x:Name="sliderX"
Grid.ColumnSpan="3"
Margin="40 25 20 15"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Value="1"
Maximum="10"
Width="400" />
<Slider x:Name="sliderY"
Orientation="Vertical"
Grid.ColumnSpan="3"
Margin="20"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Value="1"
Maximum="10"
Height="300" />
</Grid>
</Window>
在前端代码中,我们实例化了两个Button,并分别设置了ScaleTransform。第一个ScaleTransform 对象 的ScaleX和ScaleY分别绑定了一个slider,方便设置它们的放大缩放值。第二个ScaleTransform 设置了CenterX和CenterY,使其在中心位置放大缩小,最后在C#后端鼠标的移动事件下设置放大缩小值。
private void Window_MouseMove(object sender, MouseEventArgs e)
{
if (button.RenderTransform is ScaleTransform t)
{
Point point = e.GetPosition(this);
t.ScaleX = (point.X + point.Y) / 200;
t.ScaleY = (point.X + point.Y) / 200;
}
}
最后,运行之后的效果如下:
总结:ScaleX和ScaleY的默认值为1,表示不进行放大缩小,大于1时,表示放大,小于1时,表示缩小。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:090-《ScaleTransform缩放》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年11月02日
SkewTransform表示倾斜某个对象,它有两个方向的倾斜角度可以设置,AngleX表示设置x 轴倾斜角度,该角度是从 y 轴逆时针旋转后测量得到,单位为度。AngleY表示设置y 轴倾斜角度,该角度通过测量从 x 轴逆时针旋转得到的角度度数。另外,它也有CenterX和CenterY,表示倾斜转换中心的xy坐标。
public sealed class SkewTransform : Transform
{
public static readonly DependencyProperty AngleXProperty;
public static readonly DependencyProperty AngleYProperty;
public static readonly DependencyProperty CenterXProperty;
public static readonly DependencyProperty CenterYProperty;
public SkewTransform();
public SkewTransform(double angleX, double angleY);
public SkewTransform(double angleX, double angleY, double centerX, double centerY);
public double AngleX { get; set; }
public double AngleY { get; set; }
public double CenterX { get; set; }
public double CenterY { get; set; }
public override Matrix Value { get; }
public SkewTransform Clone();
public SkewTransform CloneCurrentValue();
}
一、SkewTransform示例
注意:SkewTransform 可以在XY平面中为一个对象创建 3 维深度的错觉。下面我们通过一个示例,合理的调节X和Y方面的倾斜度,就可以模拟出3维变换的错觉。
前端代码
<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="Lavender"
MouseMove="Window_MouseMove"
Title="WPF中文网 - www.wpfsoft.com" Height="350" Width="500">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0"
Width="120"
Height="120"
Background="LightBlue"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Border.RenderTransform>
<SkewTransform CenterX="0" CenterY="0"
AngleX="{Binding ElementName=sliderX,Path=Value}"
AngleY="{Binding ElementName=sliderY,Path=Value}"/>
</Border.RenderTransform>
</Border>
<Button x:Name="button"
Grid.Column="1"
Background="LightBlue"
Width="120"
Height="120"
Content="SkewTransform倾斜"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Button.RenderTransform>
<SkewTransform CenterX="60" CenterY="60"
AngleX="{Binding ElementName=sliderX,Path=Value}"
AngleY="{Binding ElementName=sliderY,Path=Value}"/>
</Button.RenderTransform>
</Button>
<Slider x:Name="sliderX"
Grid.ColumnSpan="3"
Margin="40 25 20 15"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Value="0"
Maximum="180"
Width="400" />
<Slider x:Name="sliderY"
Orientation="Vertical"
Grid.ColumnSpan="3"
Margin="20"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Value="0"
Maximum="180"
Height="300" />
</Grid>
</Window>
接下来F5运行,拖动slider,使用XY两个方向进行倾斜。
注意右边的对象,我们将转换的坐标设置到对象的中心点,这样在拖动X轴slider时,就会呈现出3维变换的效果。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:091-《SkewTransform倾斜》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年11月02日
TranslateTransform只有X和Y两个属性,分别代表X轴和Y轴上的平移距离。
public sealed class TranslateTransform : Transform
{
public static readonly DependencyProperty XProperty;
public static readonly DependencyProperty YProperty;
public TranslateTransform();
public TranslateTransform(double offsetX, double offsetY);
public double X { get; set; }
public double Y { get; set; }
public override Matrix Value { get; }
public TranslateTransform Clone();
public TranslateTransform CloneCurrentValue();
}
接下来,我们以一个例子来说明平移转换的用法。
前端代码
<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="Lavender"
MouseMove="Window_MouseMove"
MouseDown="Window_MouseDown"
MouseUp="Window_MouseUp"
Title="WPF中文网 - www.wpfsoft.com" Height="350" Width="500">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0"
Width="120"
Height="120"
Background="LightBlue"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Border.RenderTransform>
<TranslateTransform
X="{Binding ElementName=sliderX,Path=Value}"
Y="{Binding ElementName=sliderY,Path=Value}"/>
</Border.RenderTransform>
</Border>
<Border x:Name="border"
Grid.Column="1"
Background="LightGreen"
Width="120"
Height="120"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Border.RenderTransform>
<TranslateTransform/>
</Border.RenderTransform>
</Border>
<Slider x:Name="sliderX"
Grid.ColumnSpan="3"
Margin="40 25 20 15"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Value="0"
Maximum="180"
Width="400" />
<Slider x:Name="sliderY"
Orientation="Vertical"
Grid.ColumnSpan="3"
Margin="20"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Value="0"
Maximum="180"
Height="300" />
</Grid>
</Window>
在这个例子中,左边的border的TranslateTransform 对象的值直接绑定到slider,拖动两个slider就可以控制border水平和垂直方向的位置。右边的border则利用鼠标按下、移动和抬起事件,初步实现了用鼠标去移动位置的功能。
后台代码
public partial class MainWindow : Window
{
public Point DownPoint { get; private set; } = new Point(0, 0);
public bool IsMouseDown { get; private set; } = false;
public MainWindow()
{
InitializeComponent();
}
private void Window_MouseMove(object sender, MouseEventArgs e)
{
if (!IsMouseDown) return;
if (border.RenderTransform is TranslateTransform t)
{
Point point = e.GetPosition(this);
t.X = (point.X - DownPoint.X);
t.Y = (point.Y - DownPoint.Y);
}
}
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
IsMouseDown = true;
DownPoint = e.GetPosition(this);
}
private void Window_MouseUp(object sender, MouseButtonEventArgs e)
{
IsMouseDown = false;
}
}
当然,这个例子还不够完善,我们会在后面的图片查看器demo中去完善平移功能。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:092-《TranslateTransform平移》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年11月02日
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日