转换概述

了解如何通过在 UI 中更改元素的相对坐标系,在 Windows 运行时 API 中使用转换。 这可用于调整单个 XAML 元素的外观,例如缩放、旋转或转换 x-y 空间中的位置。

什么是转换?

转换 定义如何映射或转换从一个坐标空间到另一个坐标空间的点。 将转换应用于 UI 元素时,它会更改 UI 元素作为 UI 的一部分呈现到屏幕的方式。

考虑四种广泛的分类中的变换:平移、旋转、缩放和倾斜(亦称剪切)。 为了使用图形API更改UI元素的外观,通常最简单的方法是创建每次只定义一个操作的转换。 因此,Windows 运行时为每个转换分类定义一个离散类:

其中,你可能最常将 TranslateTransformScaleTransform 用于 UI 方案。

可以合并转换,并且有两个 Windows 运行时类支持此目的: CompositeTransformTransformGroup。 在 CompositeTransform中,按以下顺序应用转换:缩放、倾斜、旋转、转换。 如果希望以不同的顺序应用转换,请使用 TransformGroup 而不是 CompositeTransform。 更多信息,请参阅 CompositeTransform

转换和布局

在 XAML 布局中,转换在布局过程完成后应用,因此即在应用转换之前已做出可用空间的计算和其他布局决策。 由于布局优先,如果您对位于 网格 单元或在布局期间分配空间的类似布局容器中的元素进行转换,有时会出现意外的结果。 转换后的元素可能显示为截断或遮盖,因为它试图绘制到在父容器内划分空间时未计算转换后维度的区域。 可能需要试验转换结果并调整某些设置。 例如,不要依赖自适应布局和星型调整,可能需要更改 中心 属性或声明布局空间的固定像素度量,以确保父级分配足够的空间。

迁移说明: Windows Presentation Foundation(WPF)具有 LayoutTransform 属性,该属性在布局过程之前应用转换。 但 Windows 运行时 XAML 不支持 LayoutTransform 属性。 (Microsoft Silverlight 也没有此属性。

作为替代方法,Windows 社区工具包提供了 LayoutTransformControl,可以对应用程序的任何 FrameworkElement 应用矩阵变换。

将变换应用到 UI 元素

将转换应用于对象时,通常可以设置属性 UIElement.RenderTransform。 设置此属性并不会逐个像素更改对象。 该属性的真正功能是在该对象存在的本地坐标空间中应用变换。 然后,渲染逻辑和操作(后布局)渲染组合坐标空间,使其看起来像对象改变了外观,也可能改变了布局位置(如果应用了 TranslateTransform)。

默认情况下,每个呈现转换都以目标对象的本地坐标系(0,0)的原点居中。 唯一的例外是TranslateTransform,它没有要设置的中心属性,因为平移效果是相同的,无论其中心在哪里。 但每个其他转换都具有用于设置 CenterXCenterY 的属性。

每当对 UIElement.RenderTransform使用转换时,请记住,UIElement 上有另一个属性,会影响转换的效果:RenderTransformOrigin。 RenderTransformOrigin 声明的 是整个转换应应用于元素的默认(0,0)点,还是应用于该元素的相对坐标空间内的一些其他原点。 对于典型元素,(0,0)将转换置于左上角。 根据你想要的效果,可以选择更改 RenderTransformOrigin,而不是调整变换的 CenterXCenterY 值。 请注意,如果同时应用 RenderTransformOriginCenterX / CenterY 值,则结果可能会非常混乱,尤其是在对任何值进行动画处理时。

出于命中测试目的,应用转换的对象继续以符合 x-y 空间中的视觉外观的预期方式响应输入。 例如,如果使用 TranslateTransform 在 UI 中横向移动 矩形 400 像素,当用户按下 矩形 的位置时,矩形 将响应 PointerPressed 事件。 如果用户在 矩形 平移之前按下其所在区域,则不会收到错误事件。 对于影响命中测试的任何 z 索引注意事项,应用变换不会产生任何影响;决定哪个元素处理在 x-y 空间中某个点的输入事件的 z 索引仍然根据容器中声明的子元素顺序进行评估。 该顺序通常与在 XAML 中声明元素的顺序相同,尽管对于 Canvas 对象的子元素,可以通过将 Canvas.ZIndex 附加属性应用于子元素来调整顺序。

其他转换属性

对转换进行动画处理

转换 对象可以进行动画处理。 若要对 转换进行动画处理,请将兼容类型的动画应用于要进行动画处理的属性。 这通常意味着使用 DoubleAnimationDoubleAnimationUsingKeyFrames 对象来定义动画,因为所有变换属性都是 Double类型。 影响用于 UIElement.RenderTransform 值的转换的动画不被视为依赖动画,即使它们具有非零持续时间。 关于依赖动画的更多信息,请参阅 分镜动画

如果对属性进行动画处理,以在净视觉外观方面生成类似于转换的效果(例如,对 WidthHeight 进行动画处理,FrameworkElement 而不是应用 TranslateTransform),则此类动画几乎始终被视为依赖动画。 必须启用动画,并且动画可能存在显著的性能问题,尤其是在尝试在对象进行动画处理时支持用户交互时。 因此,最好使用转换并对其进行动画处理,而不是对动画视为依赖动画的任何其他属性进行动画处理。

若要以转换为目标,必须存在现有的 转换 作为 RenderTransform的值。 通常,在初始 XAML 中为适当的转换类型放置一个元素,有时该转换上未设置任何属性。

通常使用间接定位方法将动画应用于变换的属性。 有关间接目标语法的详细信息,请参阅 情节提要动画属性路径语法

控件的默认样式有时将变换的动画定义为其视觉状态行为的一部分。 例如,ProgressRing 的视觉状态使用动画 RotateTransform 值来“旋转”圈中的点。

下面是有关如何对转换进行动画处理的简单示例。 在本例中,它正在对 RotateTransformAngle 进行动画处理,使 矩形 围绕其视觉中心原地旋转。 本示例将 RotateTransform 命名,因此不需要采用间接动画定位。不过,您也可以将转换保持未命名状态,命名应用转换的元素,然后使用间接定位,例如 (UIElement.RenderTransform).(RotateTransform.Angle)

<StackPanel Margin="15">
  <StackPanel.Resources>
    <Storyboard x:Name="myStoryboard">
      <DoubleAnimation
       Storyboard.TargetName="myTransform"
       Storyboard.TargetProperty="Angle"
       From="0" To="360" Duration="0:0:5" 
       RepeatBehavior="Forever" />
    </Storyboard>
  </StackPanel.Resources>
  <Rectangle Width="50" Height="50" Fill="RoyalBlue"
   PointerPressed="StartAnimation">
    <Rectangle.RenderTransform>
      <RotateTransform x:Name="myTransform" Angle="45" CenterX="25" CenterY="25" />
    </Rectangle.RenderTransform>
  </Rectangle>
</StackPanel>
void StartAnimation (object sender, RoutedEventArgs e) {
    myStoryboard.Begin();
}

在运行时对参考坐标系进行考虑

UIElement 具有一个名为 TransformToVisual的方法,该方法可以生成一个 Transform,用于将两个 UI 元素的坐标参考框架关联起来。 如果将根视觉对象作为第一个参数传递,则可以使用它将元素与应用的默认引用坐标帧进行比较。 如果已从其他元素捕获输入事件,或者尝试预测布局行为而不实际请求布局传递,这非常有用。

从指针事件获取的事件数据提供访问权限,通过 GetCurrentPoint 方法,您可以指定 relativeTo 参数,以将坐标参考框架更改为特定元素,而不是应用的默认值。 此方法仅仅需要在内部应用平移变换,并在为你创建返回 PointerPoint 对象时转换 x-y 坐标数据。

以数学方式描述转换

可以在转换矩阵中描述转换。 3×3 矩阵用于描述二维 x-y 平面中的转换。 仿射变换矩阵可以相乘以实现任意数量的线性变换,如旋转和剪切,接着是平移。 相交转换矩阵的最后一列等于 (0, 0, 1),因此只需在数学说明中指定前两列的成员。

如果你有数学背景或熟悉图形编程技术,则转换的数学说明可能对你有用,这些技术也使用矩阵来描述坐标空间的转换。 有一个 变换派生类,使您能够通过其 3×3 矩阵直接表示变换:MatrixTransformMatrixTransform 有一个 Matrix 属性,该属性包含一个具有六个属性的结构: M11M12M21M22OffsetXOffsetY。 每个 矩阵 属性都使用 Double 值,对应于相交转换矩阵的六个相关值(第 1 列和第 2 列)。

列 1 第 2 列 列 3
M11 M12 0
M21 M22 0
OffsetX OffsetY 1

可以用 TranslateTransformScaleTransformRotateTransformSkewTransform 对象描述的任何转换,也可以通过具有 矩阵 值的 MatrixTransform 来描述。 但通常只需使用 TranslateTransform 和其他人,因为这些转换类的属性比在 矩阵中设置向量组件更容易概念化。 还可以更轻松地对变换的离散属性进行动画处理; 矩阵 实际上是一个结构,而不是 DependencyObject,因此它不支持各个值的动画。

一些可用于应用转换作的 XAML 设计工具会将结果序列化为 MatrixTransform。 在这种情况下,最好再次使用相同的设计工具来修改转换效果并再次序列化 XAML,而不是尝试直接在 XAML 中操作 矩阵 值。

三维转换

在 Windows 10 中,XAML 引入了一个新属性 UIElement.Transform3D,可用于使用 UI 创建 3D 效果。 为此,请使用 PerspectiveTransform3D 将共享的 3D 透视或“相机”添加到场景中,然后使用 CompositeTransform3D 来转换 3D 空间中的元素,就像您会使用 CompositeTransform 一样。 有关如何实现 3D 转换的讨论,请参阅 UIElement.Transform3D

对于仅适用于单个对象的更简单的 3D 效果,可以使用 UIElement.Projection 属性。 使用 PlaneProjection 作为此属性的值,相当于对元素应用固定透视变换和一个或多个 3D 变换。 XAML UI的三维透视效果中更详细地描述了这种类型的转换。