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的原理

从技术角度看,所有变换都使用矩阵数学改变形状的坐标。不过,使用预先构建好的变换,如TranslateTransformRotateTransformScaleTransform以及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中,没有提供类似的变换功能,需要我们进行重绘才能实现。

简而言之,就是为了方便用户使用,RotateTransformScaleTransform等类型是对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)

使用RotateTransformCenterXCenterY属性时存在明显的限制。

这些属性是使用绝对坐标定义的,也就是说我们需要知道内容的中心点的准确位置。

如果正在显示动态内容(例如,可变维度的图片或可改变尺寸的元素),就会出现问题。

这个时候我们可以通过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

相关推荐
mingupup3 小时前
为WPF应用增加项目图标
wpf
张人玉6 小时前
c#WPF基础知识
开发语言·c#·wpf
yantuguiguziPGJ15 小时前
WPF 联合 Web 开发调试流程梳理(基于 Microsoft.Web.WebView2)
前端·microsoft·wpf
Aevget15 小时前
DevExpress WPF中文教程:Data Grid - 如何使用虚拟源?(二)
.net·wpf·界面控件·devexpress·ui开发·数据网格
大美B端工场-B端系统美颜师21 小时前
工控软件开发选择难?Electron、Qt、WPF 对比
qt·electron·wpf
c#上位机1 天前
MefBootstrapper在Prism引导程序中的使用
c#·wpf·prism
没有bug.的程序员2 天前
服务治理与 API 网关:微服务流量管理的艺术
java·分布式·微服务·架构·wpf
Brianna Home2 天前
【案例实战】鸿蒙分布式调度:跨设备协同实战
华为·wpf·harmonyos
c#上位机3 天前
wpf中Grid的MouseDown 事件无法触发的原因
c#·wpf