WPF中的变换(Transform)功能详解
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
,本文没有做详细介绍,可以参考下面的链接
https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.matrixtransform?view=windowsdesktop-9.0
运行结果:
转换和坐标系统
在对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