在 WPF 4.0 中,Scale 矢量的 X 和 Y 值始终是相同的。操作事件不会提供足够的信息以各向异性的方式(即,在水平方向和垂直方向各不相同)缩放元素。
默认情况下,旋转也需要两根手指,但我们将在稍后介绍如何启用单指旋转。在任何特定 ManipulationDelta 事件中,可能需要设置所有四个属性。可使用两根手指放大某个元素,同时旋转该元素并将其移动到另一位置。
缩放和旋转始终相对于某个特定的中心点。Point 类型的 ManipulationOrigin 属性的 ManipulationDeltaEventArgs 中也提供了此中心。此原点相对于在 ManipulationStarting 事件中设置的 ManipulationContainer 而言。
您在 ManipulationDelta 事件中的工作是按以下顺序根据增量值修改被操作对象的 RenderTransform 属性:首先缩放,然后旋转,最后平移。(事实上,由于水平和垂直缩放比例是相同的,您可以切换缩放转换和旋转转换的顺序,得到的结果仍然相同。)
图 3 中的 OnManipulationDelta 方法显示了一种标准方法。Matrix 对象从操作的 Image 元素上设置的 MatrixTransform 获取。该对象通过调用 ScaleAt、RotateAt(二者相对于 ManipulationOrigin)和 Translate 进行修改。Matrix 是一个结构而不是类,因此您必须用新值替换 MatrixTransform 中的旧值,以此作为结束。
此代码可略作更改。如下所示,它使用以下语句围绕一个中心进行缩放:
matrix.ScaleAt(delta.Scale.X, delta.Scale.Y, center.X, center.Y);
这相当于平移到中心点的相反方向、进行缩放,然后重新平移:
matrix.Translate(-center.X, -center.Y);
matrix.Scale(delta.Scale.X, delta.Scale.Y);
matrix.Translate(center.X, center.Y);
同样,RotateAt 方法可以替换为:
matrix.Translate(-center.X, -center.Y);
matrix.Rotate(delta.Rotation);
matrix.Translate(center.X, center.Y);
两个相邻的 Translate 调用现在相互抵消,因此最终合成结果为:
matrix.Translate(-center.X, -center.Y);
matrix.Scale(delta.Scale.X, delta.Scale.Y);
matrix.Rotate(delta.Rotation);
matrix.Translate(center.X, center.Y);
以上方法的效率可能更高。
图 4 显示了运行中的 SimpleManipulationDemo 程序。
图 4 SimpleManipulationDemo 程序
是否启用容器?
SimpleManpulationDemo 程序的一个有趣功能是您可以同时操作两个甚至更多的 Image 元素,条件是您具备相应的硬件支持和足够多的手指。每个 Image 元素生成其自己的 ManipulationStarting 事件及其自己的 ManipulationDelta 事件系列。代码通过事件参数的 Source 属性有效地区分多个 Image 元素。
因此,很重要的一点是不要在字段中设置暗示一次只能操作一个元素的任何状态信息。
由于每个 Image 元素都将自己的 IsManipulationEnabled 属性设置为 true,因此可以同时操作多个元素。其中每个元素都可以生成唯一的操作事件系列。