转换概述Transforms overview

了解如何通过更改 UI 中元素的相对坐标系,在 Windows 运行时 API 中使用转换。Learn how to use transforms in the Windows Runtime API, by changing the relative coordinate systems of elements in the UI. 此方法可用于调整各个 XAML 元素的外观,比如缩放、旋转或转换在 x-y 空间中的位置。This can be used to adjust the appearance of individual XAML elements, such as scaling, rotating, or transforming the position in x-y space.

什么是转换?What is a transform?

转换定义了如何将各种点从一个坐标空间映射或转换到另一个坐标空间。A transform defines how to map, or transform, points from one coordinate space to another coordinate space. 将转换应用到 UI 元素时,就更改了 UI 元素作为 UI 一部分在屏幕中呈现的方式。When a transform is applied to a UI element, it changes how that UI element is rendered to the screen as part of the UI.

将转换视为四个广义的类别:转换、旋转、缩放和倾斜(或扭曲)。Think of transforms in four broad classifications: translation, rotation, scaling and skew (or shear). 出于使用图形 API 更改 UI 元素外观的目的,通常最简单的做法是创建每次只定义一个操作的转换。For the purposes of using graphics APIs to change the appearance of UI elements, it's usually easiest to create transforms that define only one operation at a time. 因此 Windows 运行时为每一种转换分类定义了一个离散类。So the Windows Runtime defines a discrete class for each of these transform classifications:

在这其中,你可能最常为 UI 方案使用 TranslateTransformScaleTransformOf these, you're likely to use TranslateTransform and ScaleTransform most often for UI scenarios.

你可以合并转换,有两种 Windows 运行时类支持此操作:CompositeTransformTransformGroupYou can combine transforms, and there are two Windows Runtime classes that support this: CompositeTransform and TransformGroup. CompositeTransform 中,按照以下顺序应用转换:缩放、倾斜、旋转、转换。In a CompositeTransform, transforms are applied in this order: scale, skew, rotate, translate. 如果你希望以不同的顺序应用转换,请使用 TransformGroup 而不是 CompositeTransformUse TransformGroup instead of CompositeTransform if you want the transforms applied in a different order. 有关详细信息,请参阅 CompositeTransformFor more info, see CompositeTransform.

转换和布局Transforms and layout

在 XAML 布局中,将在布局过程完成后应用转换,因此有关可用空间的计算和其他布局决定均在应用转换之前执行。In XAML layout, transforms are applied after the layout pass is complete, so available space calculations and other layout decisions have been made before the transforms are applied. 因为布局优先,如果转换 Grid 单元或可在布局时分配空间的相似布局容器,有时你会获得意外的结果。Because layout comes first, you'll sometimes get unexpected results if you transform elements that are in a Grid cell or similar layout container that allocates space during layout. 转换过的元素可能被截断或遮盖,因为该元素尝试绘入的区域在其父容器划分空间时未计算转换后的维度。The transformed element may appear truncated or obscured because it's trying to draw into an area that didn't calculate the post-transform dimensions when dividing space within its parent container. 你可能需要试验不同的转换结果并调整某些设置。You may need to experiment with the transform results and adjust some settings. 例如,你可能需要更改 Center 属性或声明用于布局空间的固定像素度量,而不依赖于自适应布局和比例缩放,以确保父容器分配了足够的空间。For example, instead of relying on adaptive layout and star sizing, you may need to change the Center properties or declare fixed pixel measurements for layout space to make sure the parent allots enough space.

迁移注意事项: Windows Presentation Foundation (WPF) 具有 LayoutTransform 属性,该属性会在布局传递之前应用转换。Migration note: Windows Presentation Foundation (WPF) had a LayoutTransform property that applied transforms prior to the layout pass. 但 Windows 运行时 XAML 不支持 LayoutTransform 属性。But Windows Runtime XAML doesn't support a LayoutTransform property. (Microsoft Silverlight 也没有此属性。)(Microsoft Silverlight didn't have this property either.)

作为替代,Windows 社区工具包提供了 LayoutTransformControl,它对应用程序的任何 FrameworkElement 使用矩阵转换。As an alternative, the Windows Community Toolkit provides the LayoutTransformControl that applies Matrix transformations on any FrameworkElement of your application.

将转换应用到 UI 元素Applying a transform to a UI element

将转换应用到对象时,通常进行该操作以设置属性 UIElement.RenderTransformWhen you apply a transform to an object, you typically do so to set the property UIElement.RenderTransform. 设置该属性并不是按字面意思逐个像素地更改对象。Setting this property does not literally change the object pixel by pixel. 该属性真正的作用是将转换应用到存在该对象的本地坐标空间内。What the property really does is apply the transform within the local coordinate space in which that object exists. 然后呈现逻辑和操作(布局后)将会呈现合并的坐标空间,使对象外观以及布局位置(如果应用了 TranslateTransform,位置可能更改)看起来发生了更改。Then the rendering logic and operation (post-layout) renders the combined coordinate spaces, making it look like the object has changed appearance and also potentially its layout position (if TranslateTransform was applied).

默认情况下,每个呈现转换将以目标对象本地坐标系的原点(它的 (0,0))为中心。By default, each render transform is centered at the origin of the target object's local coordinate system—its (0,0). 唯一的例外是 TranslateTransform,它不具有可设置的居中属性,因为无论位于何处,转换效果都相同。The only exception is a TranslateTransform, which has no center properties to set because the translation effect is the same regardless of where it is centered. 但是其他的每一个转换都具有设置 CenterXCenterY 值的属性。But the other transforms each have properties that set CenterX and CenterY values.

将转换与 UIElement.RenderTransform 配合使用时,请记住在 UIElement 中有另一个影响转换行为的属性 :RenderTransformOriginWhenever you use transforms with UIElement.RenderTransform, remember that there's another property on UIElement that affects how the transform behaves: RenderTransformOrigin. RenderTransformOrigin 所声明的是整个转换应用到元素的默认点 (0,0),还是应用到某个该元素相对坐标空间内的其他原点。What RenderTransformOrigin declares is whether the whole transform should apply to the default (0,0) point of an element or to some other origin point within the relative coordinate space of that element. 对于典型的元素,(0,0) 将转换放置到左上角。For typical elements, (0,0) places the transform to the top left corner. 你可能会选择更改 RenderTransformOrigin 而不是在转换上对 CenterXCenterY 值进行调整,这取决于你需要的效果。Depending on what effect you want, you might choose to change RenderTransformOrigin rather than adjusting the CenterX and CenterY values on transforms. 请注意,如果同时应用 RenderTransformOriginCenterX / CenterY 值,结果可能会相当混乱,当你为这些值中的任意一个设置动画时尤其如此。Note that if you apply both RenderTransformOrigin and CenterX / CenterY values, the results can be pretty confusing, especially if you're animating any of the values.

出于命中测试的目的,将应用转换的对象会继续以与其 x-y 空间上的视觉外观一致的预期方式响应输入。For hit-testing purposes, an object to which a transform is applied continues to respond to input in an expected way that's consistent to its visual appearance in x-y space. 比如,如果你使用了 TranslateTransformRectangle 在 UI 中横向移动 400 个像素,则当该用户按下该 Rectangle 在视觉上出现的点时,Rectangle 可以响应 PointerPressed 事件。For example, if you've used a TranslateTransform to move a Rectangle 400 pixels laterally in the UI, that Rectangle responds to PointerPressed events when the user presses the point where the Rectangle appears visually. 如果用户按下转换前 Rectangle 所在的区域,将不会获得 false 事件。You won't get false events if the user presses the area where the Rectangle was before being translated. 对于任何影响命中测试的 Z 索引注意事项,应用转换不会产生任何差异;Z 索引仍按照容器中声明的子顺序进行评估,该索引可管理哪个元素可处理 x-y 空间中的点的输入事件。For any z-index considerations that affect hit testing, applying a transform makes no difference; the z-index that governs which element handles input events for a point in x-y space is still evaluated using the child order as declared in a container. 尽管就 Canvas 对象的子元素而言,可以通过对子元素应用 Canvas.ZIndex 附加属性来调整顺序,但该顺序通常与在 XAML 中声明元素的顺序相同。That order is usually the same as the order in which you declare the elements in XAML, although for child elements of a Canvas object you can adjust the order by applying the Canvas.ZIndex attached property to child elements.

其他转换属性Other transform properties

为转换创建动画Animating a transform

可为 Transform 对象创建动画。Transform objects can be animated. 若要创建 Transform 动画,将兼容类型的动画应用到要创建动画的属性。To animate a Transform, apply an animation of a compatible type to the property you want to animate. 这通常意味着你使用 DoubleAnimationDoubleAnimationUsingKeyFrames 对象定义动画,因为所有转换属性都属于 Double 类型。This typically means you're using DoubleAnimation or DoubleAnimationUsingKeyFrames objects to define the animation, because all of the transform properties are of type Double. 即使它们的持续时间不为零,对用于 UIElement.RenderTransform 值的转换产生影响的动画也不视为从属动画。Animations that affect a transform that's used for a UIElement.RenderTransform value are not considered to be dependent animations, even if they have a nonzero duration. 有关从属动画的详细信息,请参阅情节提要动画For more info about dependent animations, see Storyboarded animations.

如果要创建属性动画以对网视觉外观产生类似于转换的效果(例如,为 FrameworkElementWidthHeight 创建动画,而不是应用 TranslateTransform),此类动画几乎总被视为从属动画。If you animate properties to produce an effect similar to a transform in terms of the net visual appearance—for example, animating the Width and Height of a FrameworkElement rather than applying a TranslateTransform—such animations are almost always treated as dependent animations. 你必须启用动画,该动画可能会有较大的性能问题,尝试在创建对象动画时支持用户交互尤其如此。You'd have to enable the animations and there could be significant performance issues with the animation, especially if you're trying to support user interaction while that object is being animated. 因此更好的方式是使用转换并为它设置动画,而不是为任何将动画视作从属动画的属性设置动画。For that reason it's preferable to use a transform and animate it rather than animating any other property where the animation would be treated as a dependent animation.

为了将转换设为目标,必须将现有的 Transform 作为 RenderTransform 的值。To target the transform, there must be an existing Transform as the value for RenderTransform. 通常会将合适的转换类型放入初始的 XAML,有时并不为该转换设置属性。You typically put an element for the appropriate transform type in the initial XAML, sometimes with no properties set on that transform.

通常使用间接的目标设定技术以将动画应用到转换的属性。You typically use an indirect targeting technique to apply animations to the properties of a transform. 有关间接目标设定语法的详细信息,请参阅情节提要动画属性路径语法For more info about indirect targeting syntax, see Storyboarded animations and Property-path syntax.

控件的默认样式有时将转换的动画定义为视觉状态行为的一部分。Default styles for controls sometimes define animations of transforms as part of their visual-state behavior. 比如,适用于 ProgressRing 的视觉状态使用动画处理过的 RotateTransform 值以使圆环中的点“旋转”。For example, the visual states for ProgressRing use animated RotateTransform values to "spin" the dots in the ring.

以下是如何为转换设置动画的一个简单示例:Here's a simple example of how to animate a transform. 在本示例中,为一个 RotateTransformAngle 创建动画,以使 Rectangle 围绕它的视觉中心旋转。In this case, it's animating the Angle of a RotateTransform to spin a Rectangle in place around its visual center. 本示例为 RotateTransform 命名,因此不需要间接动画目标设定,但你也可以使转换保持未命名状态,而命名应用了转换的元素,并使用间接目标设定,比如 (UIElement.RenderTransform).(RotateTransform.Angle)This example names the RotateTransform so doesn't need indirect animation targeting, but you could alternatively leave the transform unnamed, name the element that the transform's applied to, and use indirect targeting such as (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();
}

在运行时考虑参考坐标系Accounting for coordinate frames of reference at run time

UIElement 具有一个名为 TransformToVisual 的方法,它可以生成关联两个 UI 元素的参考坐标系的 TransformUIElement has a method named TransformToVisual, which can generate a Transform that correlates the coordinate frames of reference for two UI elements. 如果将根视觉对象作为第一个参数传递,则可以使用它将元素与应用的默认参考坐标系进行对比。You can use this to compare an element to the app's default coordinate frame of reference if you pass the root visual as the first parameter. 当从不同元素捕获了输入事件时,或尝试在未实际请求布局传递的情况下预测布局行为时,这可能很有用。This can be useful if you've captured an input event from a different element, or if you are trying to predict layout behavior without actually requesting a layout pass.

从指针事件获取的事件数据将提供 GetCurrentPoint 方法的访问权限,可以在该方法中指定 relativeTo 参数以更改特定元素而非应用默认元素的参考坐标系。Event data obtained from pointer events provides access to a GetCurrentPoint method, where you can specify a relativeTo parameter to change the coordinate frame of reference to a specific element rather than the app default. 该方法仅仅在内部应用转换,并在创建返回的 PointerPoint 对象时,为你转换 x-y 坐标数据。This approach simply applies a translate transform internally and transforms the x-y coordinate data for you when it creates the returned PointerPoint object.

以数学方式描述转换Describing a transform mathematically

转换可以从转换矩阵的方式进行描述。A transform can be described in terms of a transformation matrix. 3×3 矩阵用于描述 2D x-y 平面的转换。A 3×3 matrix is used to describe the transformations in a two-dimensional, x-y plane. 仿射转换矩阵可以相乘,以形成任意数量的线性转换,比如旋转和倾斜(扭曲)并随之转换。Affine transformation matrices can be multiplied to form any number of linear transformations, such as rotation and skew (shear), followed by translation. 由于仿射转换矩阵的最后一列等于 (0, 0, 1),因此你仅需要在数学描述中指定前两列的成员。The final column of an affine transformation matrix is equal to (0, 0, 1), so you need to specify only the members of the first two columns in the mathematical description.

如果你有数学背景或熟悉图形编程技术(同样使用矩阵描述坐标空间的转换),转换的数学描述就可能对你有用。The mathematical description of a transform might be useful to you if you have a mathematical background or a familiarity with graphics-programming techniques that also use matrices to describe transformations of coordinate space. 有一个 Transform 派生类,使你能够直接以它的 3×3 矩阵方式表达转换:MatrixTransformThere's a Transform-derived class that enables you to express a transformation directly in terms of its 3×3 matrix: MatrixTransform. MatrixTransform 具有一个 Matrix 属性,该属性保留具有六项属性的结构 :M11M12M21M22OffsetXOffsetYMatrixTransform has a Matrix property, which holds a structure that has six properties: M11, M12, M21, M22, OffsetX and OffsetY. 每个 Matrix 属性使用 Double 值,并且对应于仿射转换矩阵的六个相关值(列 1 和列 2)。Each Matrix property uses a Double value and corresponds to the six relevant values (columns 1 and 2) of an affine transformation matrix.

M11M11 M12M12 00
M21M21 M22M22 00
OffsetXOffsetX OffsetYOffsetY 11

任何能够使用 TranslateTransformScaleTransformRotateTransformSkewTransform 对象描述的转换都可以通过 MatrixTransform 使用 Matrix 值等价地描述。Any transform that you could describe with a TranslateTransform, ScaleTransform, RotateTransform, or SkewTransform object could be described equally by a MatrixTransform with a Matrix value. 但是通常只使用 TranslateTransform 和其他转换类,因为将那些转换类中的属性概念化比设置 Matrix 中的矢量组件更简单。But you typically just use TranslateTransform and the others because the properties on those transform classes are easier to conceptualize than setting the vector components in a Matrix. 为各种离散的转换属性创建动画也更简单;Matrix 事实上是一种结构而不是 DependencyObject,所以无法支持创建有动画的个别值。It's also easier to animate the discrete properties of transforms; a Matrix is actually a structure and not a DependencyObject, so it can't support animated individual values.

某些支持你应用转换操作的 XAML 设计工具会将结果序列化为 MatrixTransformSome XAML design tools that enable you to apply transformation operations will serialize the results as a MatrixTransform. 在此情况下,最好再次使用同一设计工具更改转换效果并重新将 XAML 序列化,而不要尝试直接在 XAML 中自行对 Matrix 值进行操纵。In this case it may be best to use the same design tool again to change the transformation effect and serialize the XAML again, rather than trying to manipulate the Matrix values yourself directly in the XAML.

3D 转换3-D transforms

在 Windows 10 中,XAML 引入了可用于与 UI 一起创建 3D 效果的新属性 UIElement.Transform3DIn Windows 10, XAML introduced a new property, UIElement.Transform3D, that can be used to create 3D effects with UI. 若要执行此操作,请使用 PerspectiveTransform3D 将共享的 3D 透视或“相机”添加到场景,然后使用 CompositeTransform3D 在 3D 空间中转换元素,就像使用 CompositeTransform 那样。To do this, use PerspectiveTransform3D to add a shared 3D perspective or "camera" to your scene, and then use CompositeTransform3D to transform an element in 3D space, like you would use CompositeTransform. 有关如何实现 3D 转换的讨论,请参阅 UIElement.Transform3DSee UIElement.Transform3D for a discussion of how to implement 3D transforms.

对于仅应用于单个对象的较简单的 3D 效果,可以使用 UIElement.Projection 属性。For simpler 3D effects that only apply to a single object, the UIElement.Projection property can be used. PlaneProjection 用作此属性的值等同于将固定视角转换以及一个或多个 3D 转换应用到元素。Using a PlaneProjection as the value for this property is equivalent to applying a fixed perspective transform and one or more 3D transforms to the element. XAML UI 的 3D 透视效果中更详细地介绍了此类型的转换。This type of transform is described in more detail in 3-D perspective effects for XAML UI.

相关主题Related topics