前言
這段時間的開發不會用到Blend,到年底纔會大量用到,本來打算到時候在寫Blend相關的筆記,不過看到一些朋友還比較感興趣,所以這裏提前整理了一下。
首先,我希望你記住下面幾點:
- Blend並不完全是爲Designer設計的,玩得最好的一定是Programmer
- 必須瞭解Behavior,Blend很多特性基於Behavior
Expression Blend的技術發展歷史
2007
Blend的第一個版本就可以進行基本的動畫設計。它通過提供一個Object and Timeine面板來進行動畫的設計,這和Flash有些類似。在程序中,一段動畫就是一個Timeline對象。
那麼TimeLine對象是怎樣實現動畫效果的呢?
我們首先看一下抽象類TimeLine的定義:
namespace System.Windows.Media.Animation
{
public abstract class Timeline : DependencyObject
{
public bool AutoReverse { get; set; }
public TimeSpan? BeginTime { get; set; }
public Duration Duration { get; set; }
public FillBehavior FillBehavior { get; set; }
public RepeatBehavior RepeatBehavior { get; set; }
public double SpeedRatio { get; set; }
public event EventHandler Completed;
}
}
我們查看MS文檔的描述:時間線表示時間段。它提供的屬性可以讓您指定該時間段的長度(Duration),開始時間(BeginTime),重複次數(RepeatBehavior),該時間段內時間進度的快慢(SpeedRatio)等等。從TimeLine派生的類可以提供動畫功能(例如DoubleAnimation,ColorAnimation等)。
一些時間線類:
System.Windows..::..DependencyObject
System.Windows.Media.Animation.Timeline
System.Windows.Media.Animation.ColorAnimation
System.Windows.Media.Animation.ColorAnimationUsingKeyFrames
System.Windows.Media.Animation.DoubleAnimation
System.Windows.Media.Animation.DoubleAnimationUsingKeyFrames
System.Windows.Media.Animation.ObjectAnimationUsingKeyFrames
System.Windows.Media.Animation.PointAnimation
System.Windows.Media.Animation.PointAnimationUsingKeyFrames
System.Windows.Media.Animation.Storyboard
{
public sealed class Storyboard : Timeline
{
public static readonly DependencyProperty TargetNameProperty;
public static readonly DependencyProperty TargetPropertyProperty;
public TimelineCollection Children { get; }
public void Begin();
public void Pause();
public void Resume();
public void Stop();
}
}
這裏看雖然StoryBoard同樣繼承與TimeLine,但卻比其他兄弟類多了一些屬性:Begin,Pause,Resume,Stop,還有一個TimeLine的集合屬性,以及兩個附加屬性TargetName和TargetProperty。
原來,StoryBoard纔是真正和UI線程打交道的類,它的原理大概就是這樣:一個StoryBoard對象包含一些TimeLine元素,每個TimeLine對象如DoubleAnimation定義動畫,並用StoryBoard的兩個附加屬性來描述作用於哪個元素的哪個屬性,當調用StoryBoard對象的Begin()方法時,UI線程會根據TimeLine的描述,找到對應元素的屬性,時間線內不斷修改其屬性值,這樣就實現了動畫。
值得注意的是,StoryBoard本身也是繼承自TimeLine。有人不明白,StoryBoard主要用於實現動畫而不是定義動畫,爲什麼它也要繼承自TimeLine呢?其實這是一種很好的設計模式(後面會寫一篇架構和設計模式的文章,標題暫定《誰是架構師?》),從某種程度上我們可以把StoryBoard視爲一些特定動畫的集合,UI線程將這一些動畫一起執行,然而我們可以把這個動畫集合也視爲一個特定的動畫,所以StoryBoard也繼承自TimeLine,這樣你可以把一個StoryBoard對象作爲另一個StoryBoard對象的子元素。
Blend的Objects and TimeLine面板實現的就是上述功能。在面板上點擊新建就會在XAML中新增一個StoryBoard對象,選擇不同的時間之後沒改變一個元素的某個屬性,都會增加對應屬性類型的TimeLine對象,這就實現了用Blend對動畫的編輯。
然而一個控件通常有許多狀態,在不同的狀態下會有不同的動畫組,在第一版本中Blend幾乎是無能爲力的,所幸的是微軟的Silverlight以及Blend的技術發展非常快!
2008
如前面描述,一個控件有非常複雜的狀態,如果全靠這樣一個一個修改屬性值,軟件開發將會變得非常痛苦而低效。在Blend SP1中,Blend Team革命性的提出了VSM(Visual State Manager)試圖狀態管理器,一個控件可以有很多狀態,一個狀態到另一個狀態有很多屬性值需要發生改變,這樣就需要啓動一個StoryBoard過渡不同的狀態。而VSM則管理不同的狀態,所以他們有以下關係:
給自己的控件添加狀態非常簡單,在Blend中有一個State面板:
狀態分爲狀態組VisualStateGroup以及狀態VisualState,一個VisualStateGroup包含多個VisualState,其理解的很好的一個例子是看Button控件:
CommonStates(VisualStateGroup)
Normal
MouseOver
Pressed
Disabled
FocusStates(VisualStateGroup)
Unfocused
Fouces
狀態統一由VisualStateManager管理,VisualManager類有一個附加屬性VisualStateManager.VisualStateGroups,我們看Button默認模板的定義:
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition To="MouseOver" GeneratedDuration="0:0:0.5"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Duration="0" To="1"
Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="BackgroundAnimation"/>
<ColorAnimation Duration="0" To="#F2FFFFFF"
Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)"
Storyboard.TargetName="BackgroundGradient"/>
<ColorAnimation Duration="0" To="#CCFFFFFF"
Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)"
Storyboard.TargetName="BackgroundGradient"/>
<ColorAnimation Duration="0" To="#7FFFFFFF"
Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)"
Storyboard.TargetName="BackgroundGradient"/>
</Storyboard>
</VisualState>
.......
其中VisualStateGroup還包含一個Transitions屬性,Transitions是VisualTransition的集合,VisualTransition表示控件從一個狀態過渡到另一個狀態時發生的可視行爲,其包含一個StoryBoard對象,當控件在VisualStateGroup中定義的各種狀態之間過渡時將應用Transitions中的VisualTransition對象。
通過上面的分析我們不難分析出VSM的整個邏輯:
附加屬性VisualStateManager.VisualStateGroups可以被放置於任何控件;可以通過VisualStateGroup來設置控件的狀態組,每個狀態組之間的過渡可視行爲通過設置VisualStateGroup.Transitions來實現,Transitions實際上就是一些StoryBoard的集合,可以在定義各個子控件的屬性改變;每個VisualStateGroup包含一些VisualState,VisualState包含StoryBoard屬性,當過渡到這個VisualState時會觸發這段動畫。
狀態之間的過渡控制我們可以通過VisualStateManager.GotoState()方法來控制。s
所以,VSM能讓你實現很複雜的動畫處理,可以說有了VSM之後,Blend纔開始變得強大。
2009
Blend的強大,得益於兩個東西:第一是VSM,第二是Behavior。
2009年,Blend進行了4個方面的增強:
EasingFunction
GoToStateBehavior
FluidMoveBehavior
FluidLayout
EasingFunction(緩動函數)是個很重要的增強。以前的StoryBoard在運行時,只能根據屬性的初始值和結束值進行線性改變,這樣的動畫有時候不夠生動,比如我們可能希望在前半段時間內改變快一點,或者在某個時間段回退一下,這些都可以通過EasingFunction來實現。它本質上根據一個二次方程決定屬性值的漸變,這使得我們的動畫生動得多。
每一個TimeLine的實現類幾乎都定義了EasingFunction屬性,微軟也提供了一些基本的EasingFunction,如:
-
BackEase:在某一動畫開始沿指示的路徑進行動畫處理前稍稍收回該動畫的移動。
-
BounceEase:創建彈回效果。
-
CircleEase:創建使用循環函數加速和/或減速的動畫。
-
CubicEase:創建使用公式 f(t) = t3 加速和/或減速的動畫。
-
ElasticEase:創建表示彈簧在停止前來回振盪的動畫。
-
ExponentialEase:創建使用指數公式加速和/或減速的動畫。
-
PowerEase:創建使用公式 f(t) = tp(其中,p 等於 Power 屬性)加速和/或減速的動畫。
-
QuadraticEase:創建使用公式 f(t) = t2 加速和/或減速的動畫。
-
QuarticEase:創建使用公式 f(t) = t4 加速和/或減速的動畫。
-
QuinticEase:創建使用公式 f(t) = t5 加速和/或減速的動畫。
-
SineEase:創建使用正弦公式加速和/或減速的動畫。
我們看一個例子:
<DoubleAnimation From="30" To="200" Duration="00:00:3"
Storyboard.TargetName="myRectangle"
Storyboard.TargetProperty="Height">
<DoubleAnimation.EasingFunction>
<BounceEase Bounces="2" EasingMode="EaseOut" Bounciness="2" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
在Blend中設置EasingFunction的圖示:
GotoStateBehavior是一個Behavior,它用於控制我們前面VSM描述的狀態的轉換,在Asset面板的Behaviors中,即可以看到GotoStateBehavior控件,可以將其選擇拖動到任何一個控件,即可利用Blend實現狀態轉換的邏輯。在Properties面板進行設置,設置觸發事件,要轉換的狀態等:
如我們拖動到Button控件上,會產生如下代碼:
<Button x:Name="button" Content="Button">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:GoToStateAction StateName="VisualState"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
GoToStateAction本身是繼承自IAttachedObject,這和我們前面講的Behavior的原理是一樣,這也是Blend利用Behavior的一個例子。
FluidMoveBehavior:
StoryBoard能夠做到屬性值改變過程的過渡。然而還有一種場景,那就是Silverlight中控件可以隨着界面大小的調整而重新佈局,這是通過控件的MeasureOverride和ArrangeOverride方法來實現。一般情況下,到界面重新佈局時,控件瞬間被安排到新的位置,然而有時候我們希望看到這個重新排列的過程。
我們可以自己寫邏輯實現這一功能,但是非常複雜。Behavior的用途是什麼,就是重用,所以Blend小組開發了這個Behavior。
FluidMoveBehavior也位於Asset面板中的Behaviors部分,拖動FluidMoveBehavior到一個WPF WarpPanel控件,配置的屬性即可:
可以設置AppliesTo屬性爲Children,這一當Grid的尺寸大小發生改變時,可以看到起內部元素重新排列的過程,你還可以設置緩動函數來設置這段動畫的變化效果。如下圖:
最後要介紹的是FluidLayout,它通常用於在兩種狀態之間過渡的時候,控件屬性的更改沒有應用動畫效果,而又希望平滑過渡的效果。例如,當控件從一種狀態變爲另一種狀態時,Grid.Row有1變爲2,並且Grid.Rowspan由1變爲2,這一隻要開啓FluidLayout就能看到變換過程。你可以在States面板中設置FluidLayout:
很簡單,只要點擊"Turn on FluidLayout"就能開啓狀態之間的過渡效果,當然同樣可以設置緩動函數EasingFunction。
2010
.......
暫停
2010 Blend 4發佈,這自然包含一些新特性,由於時間及篇幅關係,我打算到下一篇續寫Blend 4的一些功能。
Blend 4基本上沒有新增知識點,主要都是圍繞Behavior提供的一些很酷的功能。
所以,對於Blend,只要掌握了VSM和Behavior,我想其他的都不是問題了。
預告後面的內容是,一個Blend Team據說花了4年時間研究的功能FluidMoveTagSetBehavior,這是一個很有意思的特性。相信你和我一樣會非常感興趣,還有PathListBox,它能實現更酷的效果,當然還有其他東東,到時候再揭曉了。
Blend並不難,而且我們看到它並不是爲Designer設計的,它的許多概念都需要Programer的思維。所以其實我們是很容易去學習和利用的。多摸幾次就熟悉了。
這裏主要是講理論的,後面可能會再寫一篇操作的,看時間了,相信有了理論之後,再看一面操作,就可以了。
這裏打一個廣告,筆者現在辭職全職創業,手頭有一個計劃是和Silverlight以及Windows Azure有關的,我的QQ羣(6183299)會大力分享這些方面的技術,包括ASP.NET,Silverlight,Windows Azure,WCF,Expression Blend,WCF RIA Service等等新技術,因爲這些都是我們會用到的技術,希望在交流學習中能找到志同道合者一起創業。歡迎加入...
源代碼下載:
這篇是在Blend 4發佈的時候寫的一篇教程的基礎上改寫的
原教程下載:http://files.cnblogs.com/hielvis/Behavior2.rar
源代碼: http://files.cnblogs.com/hielvis/SLBlendDemo.rar
你需要安裝VS2010,Silverlight 4 Toolkit