創建影片面臨的第一個挑戰是為影片選擇正確的屬性,期望的結果(例如,在視窗中移動元素)與需要使用的屬性(在這種情況下是Canvas.Left和Canvas.Top屬性)之間的關系并不總是很直觀,下面是一些指導原則:
- 如果希望使用影片來使元素顯示和消失,不要使用Visibility屬性(該屬性只能在完全可見和完全不可見之間進行切換),應改用Opacity屬性淡入或淡出元素,
- 如果希望動態改變元素的位置,可考慮使用Canvas面板,它提供了最直接的屬性(Canvas.Left及Canvas.Top),而且開銷最小,此外,也可使用影片屬性在其他布局容器中獲得類似效果,例如,可通過使用ThicknessAnimation類動態改變Margin和Padding等屬性,還可動態改變Grid控制元件中的MinWidth或MinHeight屬性、一列或一行,
- 影片最常用的屬性是渲染變換,可使用變換移動或翻轉元素(TranslateTransform)、旋轉元素(RotateTransform)、縮放或扭曲元素(ScaleTransform)等,通過仔細地使用變換,有時可避免在影片中硬編碼尺寸和位置,它們也繞過了WPF布局系統,比直接作用于元素大小或位置的其他方法速度更快,
- 動態改變元素表面的較好方法是修改畫刷屬性,可使用ColorAnimation改變顏色或其他影片物件來變換更復雜畫刷的屬性,如漸變中的偏移,
接下來的示例演示了如何動態改變變換和畫刷,以及如何使用更多的一些影片型別,還將討論如何使用關鍵幀創建多段影片、如何創建基于路徑的影片和基于幀的影片,
一、動態變換
變換提供了自定義元素的最強大方式之一,當使用變換時,不只是改變元素的邊界,而且會移動、翻轉、扭曲、拉伸、放大、縮小或旋轉元素的整個可視化外觀,例如,可通過ScaleTransform動態改變按鈕的尺寸,這會改變整個按鈕的尺寸,包括按鈕的邊框及其內部的內容,這種效果比動態改變Width和Height屬性或改變文本的Fontsize屬性給人的印象更深刻,
前面章節了解到,每個元素都能以兩種不同的方式使用變換:RenderTransform屬性和LayoutTransform屬性,RenderTransform效率更高,因為是在布局之后應用變換并且勇于變換最終的渲染輸出,LayoutTransform在布局前應用,從而其他控制元件需要重新排列以適應變換,改變LayoutTransform屬性會引發新的布局操作(除非在Canvas面板上使用元素,在這種情況下,RenderTransform和LayoutTransform的效果相同),
為在影片中使用變換,第一步是定義變換(影片可改變已經存在的變換,但不能創建新的變換),例如,假設希望使按鈕旋轉,此時需要使用RotateTransform物件:
<Button Content="A Button"> <RenderTransform> <RotateTransform></RotateTransform> </RenderTransform> </Button>
現在當將滑鼠移動到按鈕上時,下面的事件觸發器就會旋轉按鈕,使用的目標屬性是RenderTransform.Angle——換句話說,讀取按鈕的RenderTransform屬性并修改其中定義的RotateTransform物件的Angle屬性,事實上,RenderTransform屬性可包含各種不同的變換物件,每種變換物件的屬性各不相同,這不會引起問題,只要使用的變換具有Angle屬性,這個觸發器就能作業:
<EventTrigger RoutedEvent="Button.MouseEnter"> <EventTrigger.Actions> <BeginStoryboard Name="rotateStoryboardBegin"> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" To="360" Duration="0:0:0.8" RepeatBehavior="Forever"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger>
按鈕在0.8秒得時間內旋轉一周并且持續旋轉,當按鈕旋轉時仍完全可用——例如,可單擊按鈕并處理Click事件,
為保證按鈕繞其中心旋轉(而不是繞左上角旋轉),需要按如下方式設定RenderTransformOrigin屬性:
<Button RenderTransformOrigin="0.5,0.5"/>
請記住,RenderTransformOrigin屬性使用0~1的相對單位,所以0.5表示中點,
為停止旋轉,可使用第二個觸發器回應MouseLeave事件,這是,可洗掉執行旋轉的故事板,但這會導致按鈕一步調回到它原來的位置,更好的方法是開始第二個影片,用它替代第一個影片,這個影片忽略To和From屬性,這意味著它無縫地再0.2秒得時間內將按鈕旋轉回原始方向:
<EventTrigger RoutedEvent="Button.MouseLeave"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" Duration="0:0:0.2"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger>
為創建旋轉的按鈕,需要為Button.Triggers集合添加這兩個觸發器,或將它們(以及變換)放到一個樣式中,并根據需要為多個按鈕應用這個樣式,例如,下面的視窗標記充滿了下圖中顯示的“能旋轉的”按鈕:
<Window x:Class="Animation.RotateButton" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="RotateButton" Height="300" Width="300"> <Window.Resources> <Style TargetType="{x:Type Button}"> <Setter Property="HorizontalAlignment" Value="Center"></Setter> <Setter Property="RenderTransformOrigin" Value="0.5,0.5"></Setter> <Setter Property="Padding" Value="20,15"></Setter> <Setter Property="Margin" Value="2"></Setter> <Setter Property="RenderTransform"> <Setter.Value> <RotateTransform></RotateTransform> </Setter.Value> </Setter> <Style.Triggers> <EventTrigger RoutedEvent="Button.MouseEnter"> <EventTrigger.Actions> <BeginStoryboard Name="rotateStoryboardBegin"> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" To="360" Duration="0:0:0.8" RepeatBehavior="Forever"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> <EventTrigger RoutedEvent="Button.MouseLeave"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" Duration="0:0:0.2"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel Margin="5" Button.Click="cmd_Clicked"> <Button>One</Button> <Button>Two</Button> <Button>Three</Button> <Button>Four</Button> <TextBlock Name="lbl" Margin="5"></TextBlock> </StackPanel> </Window>RotateButton
在單擊任何按鈕時,都會在TextBlock元素中顯示一條資訊,

這個示例還未分析渲染變換和布局變換之間的區別提供了絕佳的機會,如果修改代碼可使用LayoutTransform屬性,那么會發現當旋轉其中一個按鈕時,其他按鈕會被推離原來的位置,例如,如果旋轉最上面的按鈕,下面的按鈕會上下跳動以避開頂部的按鈕,
<Window x:Class="Animation.RotateButtonWithLayout" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="RotateButtonWithLayout" Height="300" Width="300"> <Window.Resources> <Style TargetType="{x:Type Button}"> <Setter Property="HorizontalAlignment" Value="Center"></Setter> <Setter Property="RenderTransformOrigin" Value="0.5,0.5"></Setter> <Setter Property="Padding" Value="20,15"></Setter> <Setter Property="Margin" Value="2"></Setter> <Setter Property="LayoutTransform"> <Setter.Value> <RotateTransform></RotateTransform> </Setter.Value> </Setter> <Style.Triggers> <EventTrigger RoutedEvent="Button.MouseEnter"> <EventTrigger.Actions> <BeginStoryboard Name="rotateStoryboardBegin"> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="LayoutTransform.Angle" To="360" Duration="0:0:0.8" RepeatBehavior="Forever"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> <EventTrigger RoutedEvent="Button.MouseLeave"> <EventTrigger.Actions> <!-- <RemoveStoryboard BeginStoryboardName="rotateStoryboardBegin"></RemoveStoryboard> --> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="LayoutTransform.Angle" Duration="0:0:0.2"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel Margin="5" Button.Click="cmd_Clicked"> <Button>One</Button> <Button>Two</Button> <Button>Three</Button> <Button>Four</Button> <TextBlock Name="lbl" Margin="5"></TextBlock> </StackPanel> </Window>RotateButtonWithLayout

動態改變多個變換
可很容易地組合使用變換,實際上這是很容易——只需要使用TransformGroup物件設定LayoutTransform或RenderTransform屬性即可,可根據需要在TransformGroup物件中嵌套任意多個變換,
下圖顯示了一個使用兩個變換創建的有趣效果,檔案視窗剛開始作為主視窗左上角的小縮略圖,當檔案視窗顯示時,內容旋轉、擴展并快速淡入到試圖中,從概念上講,這與最大化視窗時Windows使用的效果類似,在WPF中,可通過變換為所有的元素應用這種技巧,

為創建這種效果,在如下TransformGroup物件中定義了兩個變換,并使用TransformGroup物件設定包含所有內容的Board物件的RenderTransform屬性:
<Border.RenderTransform> <TransformGroup> <ScaleTransform></ScaleTransform> <RotateTransform></RotateTransform> </TransformGroup> </Border.RenderTransform>
通過指定數字偏移值(0用于首先顯示的ScaleTransform物件,1用于接下來顯示的RotateTransform物件),影片可與這兩個變換物件進行互動,例如,下面的影片放大內容:
<DoubleAnimation Storyboard.TargetName="element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleX" From="0" To="1" Duration="0:0:2" AccelerationRatio="1"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleY" From="0" To="1" Duration="0:0:2" AccelerationRatio="1"></DoubleAnimation>
下面的影片位于相同的故事板中,用于旋轉內容:
<DoubleAnimation Storyboard.TargetName="element" Storyboard.TargetProperty="RenderTransform.Children[1].Angle" From="70" To="0" Duration="0:0:2" ></DoubleAnimation>
這個影片中的內容比此處顯示的內容還多,例如,還有一個同事增加Opacity屬性的影片,并且當Borad元素達到最大尺寸時,它短暫地向后"反彈"一下,創建一種更趨自然的效果,為這個影片創建時間線并修改各個影片物件屬性需要耗費時間——理想情況下,可使用諸如Expression Blend的設計工具執行這些任務,而不是通過手動撰寫代碼來完成這些任務,甚至更好的情況下,只要有第三方開發者將這一邏輯分組到自定義影片中,就可以重用并根據需要將其應用到物件上(根據目前的情況,可通過將Storyboard物件存盤為應用程式級的資源,重用這個影片),
下面是完整的XAML標記:
<Window x:Class="Animation.ExpandElement" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="ExpandElement" Height="423.2" Width="488.8" WindowStartupLocation="CenterScreen"> <Window.Triggers> <EventTrigger RoutedEvent="Window.Loaded"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard SpeedRatio="1.5"> <DoubleAnimation Storyboard.TargetName="element" Storyboard.TargetProperty="Opacity" From="0.2" To="1" Duration="0:0:2.5"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="element" Storyboard.TargetProperty="RenderTransform.Children[1].Angle" From="70" To="0" Duration="0:0:2" ></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleX" From="0" To="1" Duration="0:0:2" AccelerationRatio="1"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleY" From="0" To="1" Duration="0:0:2" AccelerationRatio="1"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleX" To="0.98" BeginTime="0:0:2" Duration="0:0:0.05" DecelerationRatio="1"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleY" To="0.98" BeginTime="0:0:2" Duration="0:0:0.05" DecelerationRatio="1"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleX" To="1" BeginTime="0:0:2.05" Duration="0:0:0.2" AccelerationRatio="1"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleY" To="1" BeginTime="0:0:2.05" Duration="0:0:0.2" AccelerationRatio="1"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Window.Triggers> <Grid> <!--<Button Name="element"> <Button.Content>Text</Button.Content> <Button.RenderTransform> <TransformGroup> <ScaleTransform ScaleX="0" ScaleY="0"></ScaleTransform> <TranslateTransform></TranslateTransform> <RotateTransform Angle="90"></RotateTransform> </TransformGroup> </Button.RenderTransform> </Button>--> <Border Name="element" Margin="3" Background="LightGoldenrodYellow" BorderBrush="DarkBlue" BorderThickness="2" CornerRadius="5" > <Border.RenderTransform> <TransformGroup> <ScaleTransform></ScaleTransform> <RotateTransform></RotateTransform> </TransformGroup> </Border.RenderTransform> <FlowDocumentScrollViewer IsToolBarVisible="True"> <FlowDocument> <Paragraph xml:space="preserve">The <Italic>foof</Italic> feature is indispensable. You can configure the foof feature using the Foof Options dialog box.</Paragraph> <BlockUIContainer> <Button HorizontalAlignment="Left" Padding="5">Open Foof Options</Button> </BlockUIContainer> <Paragraph FontSize="20pt">Largest Cities in the Year 100</Paragraph> <Table> <Table.Columns> <TableColumn Width="*"></TableColumn> <TableColumn Width="3*"></TableColumn> <TableColumn Width="*"></TableColumn> </Table.Columns> <TableRowGroup > <TableRow FontWeight="Bold" > <TableCell > <Paragraph>Rank</Paragraph> </TableCell> <TableCell> <Paragraph>Name</Paragraph> </TableCell> <TableCell> <Paragraph>Population</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>1</Paragraph> </TableCell> <TableCell> <Paragraph>Rome</Paragraph> </TableCell> <TableCell> <Paragraph>450,000</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>2</Paragraph> </TableCell> <TableCell> <Paragraph>Luoyang (Honan), China</Paragraph> </TableCell> <TableCell> <Paragraph>420,000</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>3</Paragraph> </TableCell> <TableCell> <Paragraph>Seleucia (on the Tigris), Iraq</Paragraph> </TableCell> <TableCell> <Paragraph>250,000</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>4</Paragraph> </TableCell> <TableCell> <Paragraph>Alexandria, Egypt</Paragraph> </TableCell> <TableCell> <Paragraph>250,000</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>5</Paragraph> </TableCell> <TableCell> <Paragraph>Antioch, Turkey</Paragraph> </TableCell> <TableCell> <Paragraph>150,000</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>6</Paragraph> </TableCell> <TableCell> <Paragraph>Anuradhapura, Sri Lanka</Paragraph> </TableCell> <TableCell> <Paragraph>130,000</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>7</Paragraph> </TableCell> <TableCell> <Paragraph>Peshawar, Pakistan</Paragraph> </TableCell> <TableCell> <Paragraph>120,000</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>8</Paragraph> </TableCell> <TableCell> <Paragraph>Carthage, Tunisia</Paragraph> </TableCell> <TableCell> <Paragraph>100,000</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>9</Paragraph> </TableCell> <TableCell> <Paragraph>Suzhou, China</Paragraph> </TableCell> <TableCell> <Paragraph>n/a</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>10</Paragraph> </TableCell> <TableCell> <Paragraph>Smyrna, Turkey</Paragraph> </TableCell> <TableCell> <Paragraph>90,000</Paragraph> </TableCell> </TableRow> </TableRowGroup> </Table> </FlowDocument> </FlowDocumentScrollViewer> </Border> </Grid> </Window>ExpandElement
這種效果非常有用,例如,可使用該效果將注意力吸引到新的內容——例如用戶剛剛打開的檔案,這種效果可能的變化是無窮無盡的,例如,創建產品目錄時,當用戶將滑鼠懸停在相應的產品名稱上時,滑入包含產品細節的面板或將產品影像滾入試圖,
二、動態改變畫刷
動態改變畫刷是WPF影片中的另一種常用技術,和動態變換同樣容易,同樣,這種技術使用恰當的影片型別,深入到希望改變的特定子屬性,
下圖顯示了一個修改RadialGradientBrush畫刷的示例,當影片運行時,徑向漸變的中心點沿橢圓漂移,從而實作了一種三維效果,同時,外側的漸變顏色從藍色變成黑色,

為實作這個效果,需要使用兩種尚未分析過的影片型別,ColorAnimation影片在兩個顏色之間逐漸混合,創建一種微妙的顏色轉移效果,PointAnimation影片可將點從一個位置移到另一個位置(本質上與使用獨立DoubleAnimation,通過線性插值同時修改X坐標和Y坐標是相同的),可使用PointAnimation影片改變使用點構造的圖形,或者就像這個示例中那樣,改變徑向漸變中心點的位置,
下面是標記定義了橢圓及其畫刷:
<Ellipse Name="ellipse" Margin="5" Grid.Row="1" Stretch="Uniform"> <Ellipse.Fill> <RadialGradientBrush RadiusX="1" RadiusY="1" GradientOrigin="0.7,0.3"> <GradientStop Color="White" Offset="0" ></GradientStop> <GradientStop Color="Blue" Offset="1" ></GradientStop> </RadialGradientBrush> </Ellipse.Fill> </Ellipse>
下面是移動中心點以及改變第二種顏色的兩個影片:
<PointAnimationUsingKeyFrames Storyboard.TargetName="ellipse" Storyboard.TargetProperty="Fill.GradientOrigin" RepeatBehavior="Forever"> <LinearPointKeyFrame Value="0.7,0.3" KeyTime="0:0:0"></LinearPointKeyFrame> <LinearPointKeyFrame Value="0.3,0.7" KeyTime="0:0:5"></LinearPointKeyFrame> <LinearPointKeyFrame Value="0.5,0.9" KeyTime="0:0:8"></LinearPointKeyFrame> <LinearPointKeyFrame Value="0.9,0.6" KeyTime="0:0:10"></LinearPointKeyFrame> <LinearPointKeyFrame Value="0.8,0.2" KeyTime="0:0:12"></LinearPointKeyFrame> <LinearPointKeyFrame Value="0.7,0.3" KeyTime="0:0:14"></LinearPointKeyFrame> <DiscretePointKeyFrame Value="0.7,0.3" KeyTime="0:0:20"></DiscretePointKeyFrame> <DiscretePointKeyFrame Value="0.3,0.7" KeyTime="0:0:25"></DiscretePointKeyFrame> <DiscretePointKeyFrame Value="0.5,0.9" KeyTime="0:0:28"></DiscretePointKeyFrame> <DiscretePointKeyFrame Value="0.9,0.6" KeyTime="0:0:20"></DiscretePointKeyFrame> <DiscretePointKeyFrame Value="0.8,0.2" KeyTime="0:0:22"></DiscretePointKeyFrame> <DiscretePointKeyFrame Value="0.7,0.3" KeyTime="0:0:24"></DiscretePointKeyFrame> </PointAnimationUsingKeyFrames> <ColorAnimation Storyboard.TargetName="ellipse" Storyboard.TargetProperty="Fill.GradientStops[1].Color" To="Black" Duration="0:0:10" AutoReverse="True" RepeatBehavior="Forever"></ColorAnimation>
本例網站XAML標記:
<Window x:Class="Animation.AnimateRadialGradient" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="AnimateRadialGradient" Height="300" Width="300" WindowStartupLocation="CenterScreen"> <Window.Triggers> <EventTrigger RoutedEvent="Window.Loaded"> <BeginStoryboard> <Storyboard> <PointAnimationUsingKeyFrames Storyboard.TargetName="ellipse" Storyboard.TargetProperty="Fill.GradientOrigin" RepeatBehavior="Forever"> <LinearPointKeyFrame Value="0.7,0.3" KeyTime="0:0:0"></LinearPointKeyFrame> <LinearPointKeyFrame Value="0.3,0.7" KeyTime="0:0:5"></LinearPointKeyFrame> <LinearPointKeyFrame Value="0.5,0.9" KeyTime="0:0:8"></LinearPointKeyFrame> <LinearPointKeyFrame Value="0.9,0.6" KeyTime="0:0:10"></LinearPointKeyFrame> <LinearPointKeyFrame Value="0.8,0.2" KeyTime="0:0:12"></LinearPointKeyFrame> <LinearPointKeyFrame Value="0.7,0.3" KeyTime="0:0:14"></LinearPointKeyFrame> <DiscretePointKeyFrame Value="0.7,0.3" KeyTime="0:0:20"></DiscretePointKeyFrame> <DiscretePointKeyFrame Value="0.3,0.7" KeyTime="0:0:25"></DiscretePointKeyFrame> <DiscretePointKeyFrame Value="0.5,0.9" KeyTime="0:0:28"></DiscretePointKeyFrame> <DiscretePointKeyFrame Value="0.9,0.6" KeyTime="0:0:20"></DiscretePointKeyFrame> <DiscretePointKeyFrame Value="0.8,0.2" KeyTime="0:0:22"></DiscretePointKeyFrame> <DiscretePointKeyFrame Value="0.7,0.3" KeyTime="0:0:24"></DiscretePointKeyFrame> </PointAnimationUsingKeyFrames> <ColorAnimation Storyboard.TargetName="ellipse" Storyboard.TargetProperty="Fill.GradientStops[1].Color" To="Black" Duration="0:0:10" AutoReverse="True" RepeatBehavior="Forever"></ColorAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> </Window.Triggers> <Grid> <Ellipse Name="ellipse" Margin="5" Grid.Row="1" Stretch="Uniform"> <Ellipse.Fill> <RadialGradientBrush RadiusX="1" RadiusY="1" GradientOrigin="0.7,0.3"> <GradientStop Color="White" Offset="0" ></GradientStop> <GradientStop Color="Blue" Offset="1" ></GradientStop> </RadialGradientBrush> </Ellipse.Fill> </Ellipse> </Grid> </Window>AnimateRadialGradient
通過修改LinearGradientBrush和RadialGradientBrush畫刷的顏色和偏移值可創建許多精彩效果,如果還不夠,漸變畫刷還有自己的RelativeTransform屬性,可使用該屬性旋轉、縮放、拉伸以及扭曲畫刷,WPF團隊有一個有趣的稱為Gradient Obsession的工具,該工具用于構建基于漸變的影片,
VisualBrush畫刷
VisualBrush畫刷可獲取任意元素的外觀,使用該外觀可填充另一個表面,其他表面可以是任何內容,從普遍的矩形到文本框中的字母,
下圖顯示了一個基本示例,頂部是一個真實的活動按鈕,下面通過VisualBrush畫刷使用按鈕圖片填充一個矩形,并通過各種變換效果拉伸并旋轉按鈕圖片,

VisualBrush畫刷還為實作一些有趣的影片效果的影片效果提供了可能,例如,不僅可動態顯示活動的真實元素,還可動態顯示具有相同填充內容的簡單矩形,
為理解這種方法的作業原理,分析這個示例,該例將一個元素放入試圖中,當這個影片運行時,處理具有影片的元素的方法和處理其他任意WPF元素的方式相同,這意味著可單擊它內部的按鈕,或使用鍵盤滾動內容(如果用戶的操作足夠迅速的話),在一些情況下,這可能會令用戶感到困惑,在由寫情況下,這可能導致性能下降,因為需要額外的開銷來變換輸入(如滑鼠單擊),并且和原始元素一起傳遞輸入,
使用VisualBrush畫刷可輕易地代替這種效果,首先,需要創建另一個元素,使用VisualBrush畫刷填充該元素,VisualBrush畫刷必須根據希望包含影片的元素(在這個示例中,是名為visual的邊框)繪制可視化內容,
<Rectangle Grid.Row="1" Name="rectangle" Width="100" Stretch="Uniform" ClipToBounds="False" RenderTransformOrigin="0.5,0.5"> <Rectangle.Fill> <VisualBrush Visual="{Binding ElementName=visual}"> </VisualBrush> </Rectangle.Fill> <Rectangle.RenderTransform> <TransformGroup> <SkewTransform CenterX="0.5"></SkewTransform> <RotateTransform CenterX="0.5" CenterY="0.5"></RotateTransform> </TransformGroup> </Rectangle.RenderTransform> </Rectangle>
示例完整XAML標記:
<Window x:Class="Animation.AnimateVisual" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="AnimateVisual" Height="300" Width="300" Background="LightGoldenrodYellow" WindowStartupLocation="CenterScreen"> <Grid> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Button Name="visual" HorizontalAlignment="Center" VerticalAlignment="Center"> <Button.Content>Test</Button.Content> <Button.Triggers> <EventTrigger RoutedEvent="Button.Click"> <BeginStoryboard> <Storyboard RepeatBehavior="Forever"> <DoubleAnimation Storyboard.TargetName="rectangle" Storyboard.TargetProperty="RenderTransform.Children[0].AngleY" To="180" Duration="0:0:15" AutoReverse="True"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="rectangle" Storyboard.TargetProperty="RenderTransform.Children[1].Angle" To="180" Duration="0:0:20" AutoReverse="True"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="rectangle" Storyboard.TargetProperty="Opacity" To="0.1" Duration="0:0:4" AutoReverse="True"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> </Button.Triggers> </Button> <Rectangle Grid.Row="1" Name="rectangle" Width="100" Stretch="Uniform" ClipToBounds="False" RenderTransformOrigin="0.5,0.5"> <Rectangle.Fill> <VisualBrush Visual="{Binding ElementName=visual}"> </VisualBrush> </Rectangle.Fill> <Rectangle.RenderTransform> <TransformGroup> <SkewTransform CenterX="0.5"></SkewTransform> <RotateTransform CenterX="0.5" CenterY="0.5"></RotateTransform> </TransformGroup> </Rectangle.RenderTransform> </Rectangle> </Grid> </Window>AnimateVisual
為將矩形放到與原始元素相同的位置,可將它們同時放到Grid面板的同一個單元格中,改變單元格的尺寸,使其適合原始元素(邊框),并拉伸矩形使其相匹配,另一個選擇是在真實實用程式上覆寫Canvas面板(然后可將影片屬性系結到下面真實元素的ActualWidth和ActualHeight屬性,從而確保對齊),
添加矩形后,只需要調整影片來執行動態變化,最后,當影片完成時隱藏矩形:
private void storyboardCompleted(object sender,EventArgs e) { rectangle.Visibility=Visibility.Collapsed; }
三、動態改變像素著色器
通過“【WPF學習】第四十六章 效果 ”的學習,了解了像素著色器(可為任意元素應用位圖風格效果的低級例程,如模糊、輝光以及彎曲效果)的相關內容,就自身而言,像素著色器是一些有趣并且偶爾有用的工具,但通過結合使用影片,他們可變的更通用,可使用它們設計吸引眼球的過渡效果(例如,通過模糊控制元件使其淡出、隱藏,然后模糊另一個控制元件使其淡入),也可使用像素著色器創建給人留下深刻印象的用戶互動效果(例如,當用戶將滑鼠移動到按鈕上時增加按鈕上的輝光),最后為像素著色器的屬性應用影片,就像為其他內容應用影片一樣容易,
下圖顯示的頁面是基于在前面給出的旋轉按鈕示例構建的,該例包含一系列按鈕,并且當用戶將滑鼠移動到其中某個按鈕上時,關聯并開始影片,區別在于這個示例中的影片不是旋轉按鈕,而將模糊半徑減少至0,結果是移動滑鼠時,最近的按鈕驟然輕快地變得清晰,

該例的代碼和旋轉按鈕示例中的代碼相同,需要為每個按鈕提供BlurEffect物件而不是RotateTransform物件:
<Setter Property="Effect"> <Setter.Value> <BlurEffect Radius="10"></BlurEffect> </Setter.Value> </Setter>
還需要相應地修改影片:
<EventTrigger RoutedEvent="Button.MouseEnter"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Effect.Radius" To="0" Duration="0:0:0.4"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> <EventTrigger RoutedEvent="Button.MouseLeave"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Effect.Radius" To="10" Duration="0:0:0.2"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger>
本實體完整XAML標記:
<Window x:Class="Animation.BlurringButtons" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="BlurringButtons" Height="300" Width="300" WindowStartupLocation="CenterScreen"> <Window.Resources> <Style TargetType="{x:Type Button}"> <Setter Property="HorizontalAlignment" Value="Center"></Setter> <Setter Property="RenderTransformOrigin" Value="0.5,0.5"></Setter> <Setter Property="Padding" Value="20,15"></Setter> <Setter Property="Margin" Value="2"></Setter> <Setter Property="Effect"> <Setter.Value> <BlurEffect Radius="10"></BlurEffect> </Setter.Value> </Setter> <Style.Triggers> <EventTrigger RoutedEvent="Button.MouseEnter"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Effect.Radius" To="0" Duration="0:0:0.4"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> <EventTrigger RoutedEvent="Button.MouseLeave"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Effect.Radius" To="10" Duration="0:0:0.2"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel Margin="5"> <Button>One</Button> <Button>Two</Button> <Button>Three</Button> <Button>Four</Button> <TextBlock Name="lbl" Margin="5"></TextBlock> </StackPanel> </Window>BlurringButtons
為反向使用相同的方法來突出顯示按鈕,例如,可使用應用輝光效果的像素著色器突出顯示滑鼠在其上懸停的按鈕,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/2974.html
標籤:WPF
下一篇:WPF的一種動態切語言方法
