通過使用變換(transform),許多繪圖任務將更趨簡單;變換是通過不加通告地切換形狀或元素使用的坐標系統來改變形狀或元素繪製方式的對象。在WPF中,變換由繼承自System.Windows.Media.Transform抽象類的類表示。下表列出了這些類。 表 變換類 從技術角度看,所有變換都使用 ...
通過使用變換(transform),許多繪圖任務將更趨簡單;變換是通過不加通告地切換形狀或元素使用的坐標系統來改變形狀或元素繪製方式的對象。在WPF中,變換由繼承自System.Windows.Media.Transform抽象類的類表示。下表列出了這些類。
表 變換類
從技術角度看,所有變換都使用矩陣數學改變形狀的坐標。不過,使用預先構建好的變換,如TranslateTransform、RotateTransform、ScaleTransform以及SkewTransform,比使用MatrixTransform並嘗試為希望執行的操作構造正確的矩陣更簡單的多。當使用TransformGroup執行一系列變換時,WPF將所有變換融合到單獨的MatrixTransform變換中以確保獲得最佳性能。
所有變換(通過Transform類)繼承自Freezable類,這意味著它們支持自動更改通知功能。如果改變了在形狀中使用的變換,形狀會立即重新繪製自身。
變換是那些在不同上下文中非常有用的古怪概念中的一個。下麵例舉幾個例子:
- 傾斜形狀。到目前為止已經介紹了水平對齊的矩形、橢圓、直線以及多邊形。使用RotateTransform變換,可轉動坐標系統,使創建特定的形狀更容易。
- 重覆形狀。許多圖畫是在不同的位置使用類似的形狀構建的。使用變換,可先繪製一個形狀,然後移動、旋轉、縮放該形狀,以及執行其他操作。
- 動畫。通過變換,可創建大量精緻的效果。例如,旋轉形狀、將形狀從一個地方移到另一個地方,以及動態扭曲形狀。
一、變換形狀
為變換形狀,將RenderTransform屬性指定為希望使用的變換隊形。根據使用的變換隊形,需要填充不同的屬性以配置變換隊形。
例如,如果旋轉形狀,需要使用RotateTransform變換,並以度為單位提供旋轉角度。下麵的示例將舉行旋轉25°:
<Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="100"> <Rectangle.RenderTransform> <RotateTransform Angle="25" /> </Rectangle.RenderTransform> </Rectangle>
採用這種方式旋轉形狀時,是圍繞形狀的原點進行旋轉的(左上角)。下圖演示了繞形狀原點旋轉25°、50°、75°以及100°的效果。
<Window x:Class="Drawing.RotateShape" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="RotateShape" Height="427" Width="332" > <Canvas> <Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="100"> </Rectangle> <Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="100"> <Rectangle.RenderTransform> <RotateTransform Angle="25" /> </Rectangle.RenderTransform> </Rectangle> <Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="100"> <Rectangle.RenderTransform> <RotateTransform Angle="50" /> </Rectangle.RenderTransform> </Rectangle> <Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="100"> <Rectangle.RenderTransform> <RotateTransform Angle="75" /> </Rectangle.RenderTransform> </Rectangle> <Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="100"> <Rectangle.RenderTransform> <RotateTransform Angle="100" /> </Rectangle.RenderTransform> </Rectangle> </Canvas> </Window>RotateShape
有時候希望繞不同的點旋轉形狀。與其他許多變換類一樣,RotateTransform變換也提供了CenterX和CentertY屬性。可以用這些屬性指定將進行旋轉的中心。下麵的矩形使用該方法繞其中心點旋轉自身25°:
<Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="300"> <Rectangle.RenderTransform> <RotateTransform Angle="25" CenterX="45" CenterY="5" /> </Rectangle.RenderTransform> </Rectangle>
採用這種方式旋轉形狀時,是圍繞形狀的原點進行旋轉的(中心)。下圖演示了繞形狀原點旋轉25°、50°、75°以及100°的效果。
<Window x:Class="Drawing.RotateShape" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="RotateShape" Height="427" Width="332" > <Canvas> <Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="300"> </Rectangle> <Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="300"> <Rectangle.RenderTransform> <RotateTransform Angle="25" CenterX="45" CenterY="5" /> </Rectangle.RenderTransform> </Rectangle> <Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="300"> <Rectangle.RenderTransform> <RotateTransform Angle="50" CenterX="45" CenterY="5" /> </Rectangle.RenderTransform> </Rectangle> <Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="300"> <Rectangle.RenderTransform> <RotateTransform Angle="75" CenterX="45" CenterY="5" /> </Rectangle.RenderTransform> </Rectangle> <Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="300"> <Rectangle.RenderTransform> <RotateTransform Angle="100" CenterX="45" CenterY="5" /> </Rectangle.RenderTransform> </Rectangle> </Canvas> </Window>RotateShape
使用RotateTransform的CenterX和CenterY屬性時存在明顯的限制。這些屬性是使用絕對坐標定義的,這意味著需要瞭解繪製內容的中心店的準確位置。如果正在顯示動態內容(例如,可變維度的圖片或改變尺寸的元素),就會出現問題。幸運的是,WPF通過方便的RenderTransformOrigin屬性,為這個問題提供瞭解決方法,所以形狀都支持RenderTransformOrign屬性。該屬性使用相對坐標系統設置中心點,下該對坐標系統在兩個方向上的範圍都是從0到1。換句話說,點(0,0)被指定為左上角,點(1,1)表示右下角(如果形狀區域不是正方形,那麼會相應地拉伸坐標系統)。
藉助於RenderTransformOrigin屬性,可使用如下所示的標記,繞中心點旋轉任意形狀:
<Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow" Canvas.Left="100" Canvas.Top="300" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="75" CenterX="45" CenterY="5" /> </Rectangle.RenderTransform> </Rectangle>
因為不管形狀的尺寸是多少,點(0.5,0.5)都表示形狀中心,所以上面的標記可以工作。實際上,RenderTransformOrigin屬性通常比CenterX和CenterY屬性更有用,儘管根據需要可以使用兩者中的一個,或者同時使用兩者。
二、變換元素
RenderTransform和RenderTransformOrigin屬性並不限制只能用於形狀。實際上,Shape類的這些屬性從UIElement類繼承而來,這意味著所有WPF元素都支持這兩個屬性,包括按鈕、文本框、TextBlock控制項、充滿內容的整個佈局容器等。令人感到驚訝的是,可旋轉、扭曲以及縮放WPF用戶界面中的任意一部分。
RenderTransform不是在WPF基類中定義的唯一與變換相關的屬性。FrameworkElement類還定義了LayoutTransform屬性。LayoutTransform屬性以相同的方式變換元素,但在佈局之前執行其工作。這種情況的開銷雖然更大些,但如果使用佈局容器為一組控制項提供自動佈局功能,這種方式是很關鍵的(Shape類也提供了LayoutTransform屬性,但很少需要使用該屬性,因此通常使用容器(如Canvas面板)明確地放置形狀,而不是使用自動佈局)。
為理解兩者的區別,分析下圖中顯示的視窗,該視窗包含兩個StackPanel容器(由陰影區域表示),這兩個容器都包含一個選擇過的按鈕和一個正常的按鈕。在第一個StackPanel容器中,選擇的按鈕使用RenderTransform方法。該StackPanel容器在對兩個按鈕進行佈局時,第一個按鈕正常定位,並且在即將呈現之前旋轉該按鈕。因此,選擇過的按鈕被重疊在下麵。在第二個StackPanel容器中,選擇過的按鈕使用LayoutTransform方法。StackPanel容器獲取到選項後按鈕所需的邊界,並相應地佈局第二個按鈕。
<Window x:Class="Drawing.RotateElement" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="RotateElement" Height="314" Width="305" > <StackPanel> <StackPanel Margin="25" Background="LightYellow"> <Button Padding="5" HorizontalAlignment="Left"> <Button.RenderTransform> <RotateTransform Angle="35" CenterX="45" CenterY="5" /> </Button.RenderTransform> <Button.Content>I'm rotated 35 degrees</Button.Content> </Button> <Button Padding="5" HorizontalAlignment="Left">I'm not</Button> </StackPanel> <StackPanel Margin="25" Background="LightYellow"> <Button Padding="5" HorizontalAlignment="Left"> <Button.LayoutTransform> <RotateTransform Angle="35" CenterX="45" CenterY="5" /> </Button.LayoutTransform> <Button.Content>I'm rotated 35 degrees</Button.Content> </Button> <Button Padding="5" HorizontalAlignment="Left">I'm not</Button> </StackPanel> </StackPanel> </Window>RotateElement
只有很少幾個元素不能被變換,因為他們的呈現工作並非由WPF本身負責。不能被變換的元素的兩個例子是WindowsFormHost和WebBrower元素,WindowsFormHost元素用於在WPF視窗中放置Windows窗體控制項,WebBrower元素用於顯示HTML內容。
在一定程度上,當設置LayoutTransform或RenderTransform屬性時,WPF元素不知道它們正在被修改。特別是,變換不會影響元素的ActualHeight和ActualWidth屬性,它們仍記錄著變換之前的值。這正是WPF能夠保證流失佈局以及外邊距繼續以相同的方式工作的部分原理,即使應用了一個或多個變換也同樣如此。