Transform
在WPF中,我们可以通过变换(Transform
),对UI对象进行旋转、缩放、移动(平移)和倾斜等操作
通过使用变换(transform),许多绘图任务将更趋简单;
在 WPF 中,变换由继承自System.Windows.Media.Transform
抽象类的类表示,
常用的Transform
派生类如下所示
类型 | 描述 | 常用属性 | 示意图 |
---|---|---|---|
RotateTransform | 旋转坐标系统。正常绘制的形状绕着选择的中心点旋转 | Angle:角度 CenterX:旋转中心坐标-X CenterY:旋转中心坐标-Y | ![]() |
ScaleTransform | 放大或缩小坐标系统,从而绘制更大或更小的图形。 可在X和Y方向应用不同的缩放度,从而拉伸或压缩形状 | ScaleX:X方向的缩放度 ScaleY:Y方向的缩放度 CenterX:缩放中心坐标-X CenterY:缩放中心坐标-Y | ![]() |
SkewTransform | 通过倾斜一定的角度扭曲坐标系统。 例如,如果绘制正方形,通过该变换正方形会变成平行四边形 | AngleX:X方向的倾斜度 AngleY:Y方向的倾斜度 CenterX:倾斜中心坐标-X CenterY:倾斜中心坐标-Y | ![]() |
TranslateTransform | 将坐标系统移动一定距离。 | X:X方向偏移距离 Y:Y方向偏移距离 | ![]() |
另外还有两种复杂一点的派生类型
类型 | 描述 |
---|---|
TransformGroup | 组合多个变换,从而可以一次应用所有这些变换。应用变换的顺序是很重要的,因为这会影响最终结果。 例如,首先使用RotateTransform旋转形状,然后使用TranslateTransform移动形状,这样做的结果和先移动再旋转的结果是不同的 |
MatrixTransform | 使用提供的矩阵的乘积修改坐标系统。这是最复杂的选择------为实现该变换,需要掌握一些数学技巧 |
Transform的原理
从技术角度看,所有变换都使用矩阵数学改变形状的坐标。不过,使用预先构建好的变换,如TranslateTransform
、 RotateTransform
、ScaleTransform
以及SkewTransform
,
比使用MatrixTransform
并尝试为希望执行的操作构造正确的矩阵要简单得多。
底层调用来说,都是使用了MILCMD_MATRIXTRANSFORM
类型作为最终传递的数据结构
1 [StructLayout(LayoutKind.Explicit, Pack=1)]
2 internal struct MILCMD_MATRIXTRANSFORM
3 {
4 [FieldOffset(0)] internal MILCMD Type;
5 [FieldOffset(4)] internal DUCE.ResourceHandle Handle;
6 [FieldOffset(8)] internal MilMatrix3x2D Matrix;
7 [FieldOffset(56)] internal DUCE.ResourceHandle hMatrixAnimations;
8 };
当使用TransformGroup
执行一系列变换时,WPF将所有变换融合到单独的MatrixTransform
变换中以确保获得最佳性能。
在win32编程或winform中,没有提供类似的变换功能,需要我们进行重绘才能实现。
简而言之,就是为了方便用户使用,RotateTransform
、ScaleTransform
等类型是对MatrixTransform
类型进行了再封装。
变换元素(Transforming a FrameworkElement)
这里分为了两种类型
-
LayoutTransform -- 在布局过程开始前应用的变换。 应用转换后,布局系统将处理元素的转换大小和位置。
-
RenderTransform -- 修改元素外观的转换,但在布局处理完成后应用。 通过使用属性 RenderTransform 而不是 LayoutTransform 属性,可以获得性能优势。
这两种类型的应用场景:
尽可能使用 RenderTransform 属性,尤其是在使用动画 Transform 对象时。
如果需要元素在进行缩放、旋转或倾斜时,父级调整为元素变换后的大小,可以使用LayoutTransform属性,
下面我们来演示一下
我们在界面上放置一个Image
控件,然后来看一下当使用不同Transform
时,它呈现的效果。
1 <Border Grid.Row="1" BorderThickness="1" BorderBrush="Black" VerticalAlignment="Center">
2 <StackPanel>
3 <Label Content="未进行变换 图像宽=200 高=150"></Label>
4 <Image Source="img.jpg" Height="200" Width="150"></Image>
5 </StackPanel>
6 </Border>
RotateTransform
1 <Border BorderThickness="1" BorderBrush="Black" >
2 <StackPanel>
3 <Label Content="RotateTransform Angle=90 CenterX=75 CenterY=100"></Label>
4 <Image Source="img.jpg" Height="200" Width="150">
5 <Image.RenderTransform>
6 <!--旋转中心点75,100-->
7 <!--角度:90度-->
8 <RotateTransform Angle="90" CenterX="75" CenterY="100"></RotateTransform>
9 </Image.RenderTransform>
10 </Image>
11 </StackPanel>
12 </Border>
ScaleTransform
1 <Border BorderThickness="1" BorderBrush="Black" Grid.Row="1">
2 <StackPanel>
3 <Label Content="ScaleTransform ScaleX=0.8 ScaleY=0.8 CenterX=75 CenterY=100"></Label>
4 <Image Source="img.jpg" Height="200" Width="150">
5 <Image.RenderTransform>
6 <!--缩放中心点是75,100-->
7 <!--水平缩放0.8 垂直缩放0.7-->
8 <ScaleTransform ScaleX="0.8" ScaleY="0.8" CenterX="75" CenterY="100"></ScaleTransform>
9 </Image.RenderTransform>
10 </Image>
11 </StackPanel>
12 </Border>
SkewTransform
1 <Border BorderThickness="1" BorderBrush="Black" Grid.Row="2">
2 <StackPanel>
3 <Label Content="SkewTransform AngleX=10 AngleY=10 CenterX=75 CenterY=100"></Label>
4 <Image Source="img.jpg" Height="200" Width="150">
5 <Image.RenderTransform>
6 <!--倾斜中心点是75,100-->
7 <!--水平倾斜10度 垂直倾斜10度-->
8 <SkewTransform AngleX="10" AngleY="10" CenterX="75" CenterY="100"></SkewTransform>
9 </Image.RenderTransform>
10 </Image>
11 </StackPanel>
12 </Border>
TranslateTransform
1 <Border BorderThickness="1" BorderBrush="Black" Grid.Row="3">
2 <StackPanel>
3 <Label Content="TranslateTransform X=50 Y=20"></Label>
4 <Image Source="img.jpg" Height="200" Width="150">
5 <Image.RenderTransform>
7 <!--水平偏移100 垂直偏移20-->
8 <TranslateTransform X="100" Y="20"></TranslateTransform>
9 </Image.RenderTransform>
10 </Image>
11 </StackPanel>
12 </Border>
TransformGroup
1 <Border BorderThickness="1" BorderBrush="Black" Grid.Row="1">
2 <StackPanel>
3 <Label Content="ScaleTransform ScaleX=0.8 ScaleY=0.8 CenterX=75 CenterY=100"></Label>
4 <Image Source="img.jpg" Height="200" Width="150">
5 <Image.RenderTransform>
6 <TransformGroup>
7 <!--缩放中心点是75,100-->
8 <!--水平缩放0.8 垂直缩放0.7-->
9 <ScaleTransform ScaleX="0.8" ScaleY="0.8" CenterX="75" CenterY="100"></ScaleTransform>
10 <!--倾斜中心点是75,100-->
11 <!--水平倾斜10度 垂直倾斜10度-->
12 <TranslateTransform X="100" Y="20"></TranslateTransform>
13 </TransformGroup>
14 </Image.RenderTransform>
15 </Image>
16 </StackPanel>
17 </Border>
MatrixTransform
1 <Border BorderThickness="1" BorderBrush="Black" Grid.Row="2">
2 <StackPanel>
3 <Label Content="Matrix OffsetX=15 OffsetY=10 M11=1 M12=1 M21=0.1 M22=1"></Label>
4 <Image Source="img.jpg" Height="200" Width="150">
5 <Image.RenderTransform>
6 <MatrixTransform x:Name="myMatrixTransform">
7 <MatrixTransform.Matrix >
8 <Matrix OffsetX="15" OffsetY="10" M11="1" M12="1" M21="0.1" M22="1"/>
9 </MatrixTransform.Matrix>
10 </MatrixTransform>
11 </Image.RenderTransform>
12 </Image>
13 </StackPanel>
14 </Border>
关于MatrixTransform
,本文没有做详细介绍,可以参考下面的链接
运行结果:

转换和坐标系统
在对WPF中的对象进行转换(Transform
)时,不仅仅是转换了这个对象,而且还包括了该对象所在的坐标空间。
默认情况下,转换以目标对象的坐标系的原点为中心:(0,0)
使用RotateTransform
的 CenterX
和 CenterY
属性时存在明显的限制。
这些属性是使用绝对坐标定义的,也就是说我们需要知道内容的中心点的准确位置。
如果正在显示动态内容(例如,可变维度的图片或可改变尺寸的元素),就会出现问题。
这个时候我们可以通过UIElement.RenderTransformOrigin
属性使用相对坐标系统设置中心点。相对坐标系统在两个方向上的范围都是从0到1。
换句话说,点(0,0)被指定为左上角,点(1,1)表示右下角(如果形状区域不是正方形,那么会相应地拉伸坐标系统)。
借助于RenderTransformOrigin
属性,可使用如下所示的代码,绕中心点旋转任意元素:
1 <Border BorderThickness="1" BorderBrush="Black" Grid.Row="3">
2 <StackPanel>
3 <Label Content="RotateTransform Angle=90 通过RenderTransformOrigin指定中心点"></Label>
4 <Image Source="img.jpg" Height="200" Width="150" RenderTransformOrigin="0.5,0.5">
5 <Image.RenderTransform>
6 <RotateTransform Angle="90"></RotateTransform>
7 </Image.RenderTransform>
8 </Image>
9 </StackPanel>
10 </Border>
注意:在WPF中只有少量元素不能使用Transform,例如WindowsFormHost和WebView2
示例代码
参考资料:
https://learn.microsoft.com/en-us/dotnet/desktop/wpf/graphics-multimedia/transforms-overview