Главная » Разработка для Windows Phone 7 » Геометрические элементы и трансформации Windows Phone 7

0

Чтобы с помощью EllipseGeometry отрисовать эллипс с наклонными осями, применяем RotateTransform. И у нас есть выбор. Поскольку Path наследуется от UIElement, мы можем применить RotateTransform к свойству RenderTransform элемента Path:

<Grid Background="LightCyan"> <Path Stroke="Maroon"

StrokeThickness="8" Fill="Green"> <Path.Data>

<EllipseGeometry Center="250 150" RadiusX="150" RadiusY="10 0" />

</Path.Data> <Path.RenderTransform>

<RotateTransform Angle="45"

CenterX="250" CenterY="150" /> </Path.RenderTransform> </Path> </Grid>

Обратите внимание, что свойствам CenterX и CenterY объекта RotateTransform заданы те же значения, что и свойству Center самого EllipseGeometry, т.е. эллипс будет поворачиваться вокруг своего центра. При работе с объектами Path и Geometry обычно проще задать фактический центр трансформации, чем использовать RenderTransformOrigin. Обычно для RenderTransformOrigin задаются относительные координаты, например, (0.5, 0.5) определяет центр, но посмотрим, к чему это приводит в данном случае:

<Grid Background="LightCyan"> <Path Stroke="Maroon"

StrokeThickness="8" Fill="Green"

RenderTransformOrigin="0.5 0.5"> <Path.Data>

<EllipseGeometry Center="250 150" RadiusX="150" RadiusY="10 0" />

</Path.Data>

<Path.RenderTransform>

<RotateTransform Angle="45" /> </Path.RenderTransform> </Path> </Grid>

В данном случае проблема в том, что элемент Path достаточно велик, чтобы вместить EllipseGeometry с центром в точке (250, 150) и RadiusX и RadiusY равными 150 и 100, соответственно. При таких параметрах элемент Path должен быть как минимум 400 пикселов шириной и 250 пикселов высотой. (На самом деле он немного больше из-за ненулевого StrokeThickness.) Центр этого Path находится примерно в точке (200, 125). Кроме того, как и у остальных элементов, свойства HorizontalAlignment и VerticalAlignment элемента Path по умолчанию имеют значение Stretch, так что он действительно заполняет свой контейнер, каковым в данном случае является квадрат со стороной 480 пикселов, и вращение выполняется вокруг точки (240, 240).

Также можно применить трансформацию к самому объекту Geometry:

<Grid Background="LightCyan"> <Path Stroke="Maroon"

StrokeThickness="8" Fill="Green"> <Path.Data>

<EllipseGeometry Center="250 150" RadiusX="150" RadiusY="10 0"> <EllipseGeometry.Transform> <RotateTransform Angle="45"

CenterX="250" CenterY="150"

/>

</EllipseGeometry.Transform> </EllipseGeometry> </Path.Data> </Path> </Grid>

Получаемый результат выглядит абсолютно точно так же, как и в предыдущем примере, в котором CenterX и CenterY для RotateTransform задавались явно. Но результаты трансформаций могут сильно отличаться в зависимости от того, к свойству RenderTransform какого объекта, Path или Geometry, они применяются.

Свойство RenderTransform не оказывает влияния на то, как элемент воспринимается системой компоновки, а вот свойство Transform класса меняет воспринимаемые размеры элемента. Чтобы увидеть эту разницу, заключим Path с EllipseGeometry в центрированный Border:

<Grid Background="LightCyan"> <Border BorderBrush="Red"

BorderThickness="3" HorizontalAlignment="Center" VerticalAlignment="Center"> <Path Stroke="Maroon"

StrokeThickness="8" Fill="Green"> <Path.Data>

<EllipseGeometry Center="150 50" RadiusX="150" RadiusY="50" />

</Path.Data> </Path> </Border> </Grid>

Я намеренно задал свойству Center объекта EllipseGeometry те же два значения, что и свойствам RadiusX и RadiusY, так Path будет занимать именно столько места, сколько необходимо для визуального представления эллипса.

Теперь зададим RenderTransform элемента Path для реализации трансформации вращением:

<Grid Background="LightCyan"> <Border BorderBrush="Red"

BorderThickness="3" HorizontalAlignment="Center" VerticalAlignment="Center"> <Path Stroke="Maroon"

StrokeThickness="8" Fill="Green"> <Path.Data>

<EllipseGeometry Center="150 50" RadiusX="150" RadiusY="50" />

</Path.Data> <Path.RenderTransform>

<RotateTransform Angle="90"

CenterX="150" CenterY="50" /> </Path.RenderTransform> </Path> </Border> </Grid>

Как было четко показано ранее в главе 8, RenderTransform не влияет на то, как элемент воспринимается системой компоновки. Border по-прежнему определяет собственные размеры на основании исходного, не развернутого, Path. Применение трансформации к EllipseGeometry приводит совершенно к другому результату:

<Grid Background="LightCyan"> <Border BorderBrush="Red"

BorderThickness="3" HorizontalAlignment="Center" VerticalAlignment="Center"> <Path Stroke="Maroon"

StrokeThickness="8" Fill="Green"> <Path.Data>

<EllipseGeometry Center="150 50" RadiusX="150" RadiusY="50"> <EllipseGeometry.Transform> <RotateTransform Angle="90"

CenterX="150"

CenterY="50"

/>

</EllipseGeometry.Transform> </EllipseGeometry> </Path.Data> </Path> </Border> </Grid>

Но это тоже не выглядит правильным! Что произошло?

EllipseGeometry определяет эллипс, верхний левый угол ограничивающего прямоугольника которого располагается в точке (0, 0), а нижний правый угол – в точке (300, 100). Этот эллипс поворачивается на 90° вокруг точки (150, 50). Верхний левый угол ограничивающего прямоугольника развернутого эллипса располагается в точке (100, -100), и нижний правый угол – в точке (200, 200). Элемент Border занимает квадрат со стороной 200 пикселов, чтобы вместить нижний правый угол, но точки с отрицательными координатами оказываются вне Border.

Чтобы все выполнялось «правильно», центр вращения необходимо задать в точке (50, 50):

<Grid Background="LightCyan"> <Border BorderBrush="Red"

BorderThickness="3" HorizontalAlignment="Center" VerticalAlignment="Center"> <Path Stroke="Maroon"

StrokeThickness="8" Fill="Green"> <Path.Data>

<EllipseGeometry Center="150 50" RadiusX="150" RadiusY="50"> <E 11 і p s e Ge orne t r у. T r a n s f о r m> <RotateTransform Angle="90"

CenterX="50" CenterY="50"

/>

</EllipseGeometry.Transform> </EllipseGeometry> </Path.Data> </Path> </Border> </Grid>

Еще одно отличие между свойством RenderTransform элемента Path и свойством Transform объекта Geometry выявляется при использовании ScaleTransform. Начнем с небольшого прямоугольника, выровненного по левому краю:

<Grid Background="LightCyan"> <Path Stroke="Maroon"

StrokeThickness="4" Fill="Green"> <Path.Data>

<RectangleGeometry

Rect="2 220 40 40" /> </Path.Data> </Path> </Grid>

На самом деле я поместил RectangleGeometry в точке (2, 220), учитывая значение StrokeThickness элемента Path, чтобы не создавалось впечатление, что отображаемый объект выходит за рамки своего контейнера.

Теперь увеличим ширину элемента в 10 раз, применив ScaleTransform к RectangleGeometry:

<Grid Background="LightCyan"> <Path Stroke="Maroon"

StrokeThickness="4" Fill="Green"> <Path.Data>

<RectangleGeometry

Rect="2 220 40 40"> <RectangleGeometry.Transform>

<ScaleTransform ScaleX="10" /> </RectangleGeometry.Transform> </RectangleGeometry> </Path.Data> </Path> </Grid>

Теперь ширина фигуры увеличилась в 10 раз, и объект RectangleGeometry выровнен по точке (20, 220). А вот если применить эту трансформацию к элементу Path, получаем совершенно другой эффект:

<Grid Background="LightCyan"> <Path Stroke="Maroon"

StrokeThickness="4" Fill="Green"> <Path.Data>

<RectangleGeometry

Rect="2 220 40 40" /> </Path.Data> <Path.RenderTransform>

<ScaleTransform ScaleX="10" /> </Path.RenderTransform> </Path> </Grid>

Теперь в 10 раз увеличилась толщина обводки справа и слева!

Источник: Чарльз Петзольд, Программируем Windows Phone 7, Microsoft Press, © 2011.

По теме:

  • Комментарии