這是很是使人沮喪的。如此簡單的東西(並且是大多開發者會考慮尋找的東西)在WPF中卻不被以爲是繪製形狀的要求。canvas
我跑題了。現在咱們什麼也作不了。app
你可以使用Blend。但是因爲咱們大多數要輸入代碼。Blend可能有點過分了。dom
<Window x:Class="WpfAnimationTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WPF Animation Testing" Height="600" Width="800" WindowStartupLocation="CenterScreen"> <Canvas x:Name="Root" Background="Black"> </Canvas> </Window>你會看到。除了將背景變爲黑色,咱們改變了默認的grid爲canvas。並且設置了窗口大小和標題。
改變的也很少。不像大多說WPF/XAML項目,這裏咱們畫的大部分用代碼實現。函數
首先是一點兒理論佈局
好比,假設你想要在中間使用從紅到藍顏色漸變,而後變綠,你可能在0%處建立紅色點。在50%建立藍色,100%處建立綠色。動畫
WPF圖畫引擎而後在所有顏色間填充。這樣你就獲得從一個顏色到下一個的平滑過渡。ui
public MainWindow() { InitializeComponent(); Rectangle myRect = new Rectangle { Width = 300, Height = 100, Stroke = Brushes.White, StrokeThickness = 1 }; Root.Children.Add(myRect); Canvas.SetLeft(myRect, 100); Canvas.SetTop(myRect, 100); }當你按下F5,你應該能看到黑色背景上白色矩形,距離每個角都是100像素。大小300像素*100像素。需要Canvas SetLeft和SetTop調用,是因爲微軟決定贊成繪製閉環形狀的不論什麼人來決定形狀繪製的位置時沒實用處的。
public MainWindow() { InitializeComponent(); Rectangle myRect = new Rectangle { Width = 300, Height = 100, Stroke = Brushes.White, StrokeThickness = 1, Fill=Brushes.Red }; Root.Children.Add(myRect); Canvas.SetLeft(myRect, 100); Canvas.SetTop(myRect, 100); }你也可以設置矩形全局的實心填充顏色。
然而。實心顏色有點無趣。this
咱們將改動成更加有趣的東西。spa
輸入例如如下代碼:code
namespace WpfAnimationTest { public class BarDescriptor { public int RectangleX { get; set; } public int RectangleY { get; set; } public int RectangleWidth { get; set; } public int RectangleHeight { get; set; } public int AnimationTimeInSeconds { get; set; } // 0.0 to 1.0 public float BarBaseRedLevel { get; set; } public float BarBaseGreenLevel { get; set; } public float BarBaseBlueLevel { get; set; } public float GradientStartX { get; set; } public float GradientStartY { get; set; } public float GradientEndX { get; set; } public float GradientEndY { get; set; } } }確保依照你的需要改動了命名空間。
using System; using System.Linq; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; namespace WpfAnimationTest { public partial class MainWindow { private Rectangle _testRect; public MainWindow() { InitializeComponent(); Loaded += MainWindowLoaded; } private void MainWindowLoaded(object sender, RoutedEventArgs e) { BarDescriptor barOne = new BarDescriptor { RectangleX = 100, RectangleY = 100, RectangleWidth = 200, RectangleHeight = 200, AnimationTimeInSeconds = 0, BarBaseRedLevel = 0, BarBaseGreenLevel = 0, BarBaseBlueLevel = 0, GradientStartX = 0, GradientStartY = 0, GradientEndX = 0, GradientEndY = 0 }; CreateRectangleAnimatedRectangle(barOne); } private void CreateRectangleAnimatedRectangle(BarDescriptor inputParameters) { _testRect = new Rectangle { Width = inputParameters.RectangleWidth, Height = inputParameters.RectangleHeight, Stroke = Brushes.White, StrokeThickness = 1, }; Root.Children.Add(_testRect); Canvas.SetLeft(_testRect, inputParameters.RectangleX); Canvas.SetTop(_testRect, inputParameters.RectangleY); } } }再一次。確保輸入正確的命名空間。正如以前的樣例,執行時你應該又看到白色矩形。但是現在你也應該能夠輕鬆加入新矩形。經過建立新的「BarDescriptor」對象,並設置對應參數。
BarDescriptor barOne = new BarDescriptor { RectangleX = 0, RectangleY = 0, RectangleWidth = 800, RectangleHeight = 600, AnimationTimeInSeconds = 0, BarBaseRedLevel = 0, BarBaseGreenLevel = 0, BarBaseBlueLevel = 0, GradientStartX = 0, GradientStartY = 0, GradientEndX = 0, GradientEndY = 0 };這樣會建立和主窗體相同大小的矩形。
透明度的設置贊成你控制多少背景、多少顏色顯示出來。
GradientStopCollection gradientStops = new GradientStopCollection { new GradientStop(Color.FromScRgb(0.0f, 1, 1, 1), 0.0), new GradientStop(Color.FromScRgb(0.0f, 1, 1, 1), 0.01), new GradientStop(Color.FromScRgb(0.5f, 1, 1, 1), 0.02), new GradientStop(Color.FromScRgb(1.0f, 1, 1, 1), 0.03), new GradientStop(Color.FromScRgb(0.5f, 1, 1, 1), 0.04), new GradientStop(Color.FromScRgb(0.0f, 1, 1, 1), 0.05), new GradientStop(Color.FromScRgb(0.0f, 1, 1, 1), 1.0), };這一系列的漸變點建立了一系列七色點全白(R/G/B值都爲1),顏色點被設置沿着漸變填充長度 位置爲 0, 0.01, 0.02, 0.03, 0.04, 0.05,和1。並且有透明度0, 0, 0.5, 1, 0.5, 0 和0。這系列填充意味着咱們從第一個點到第二個點透明,而後忽然從全然透明升級爲實心白色,緊接着忽然降回透明;最後,從點6和點7(矩形的剩餘部分)是100%透明。
LinearGradientBrush gradientBrush = new LinearGradientBrush(gradientStops, new Point(0, 0.5), new Point(1, 0.5));這將使用點集建立實際的漸變。它將橫跨Y座標系,沿着X軸從0到100%(1)水平執行。
一旦你添加了漸變。改動了矩形建立參數來設置漸變,當你這樣作了。也會使得邊界消失:
_testRect = new Rectangle { Width = inputParameters.RectangleWidth, Height = inputParameters.RectangleHeight, Stroke = Brushes.Transparent, StrokeThickness = 0, Fill = gradientBrush };這些都作好後,執行你的應用程序,你會獲得:
DoubleAnimation firstStopAnim =new DoubleAnimation(0.01, 0.95,new Duration(new TimeSpan(0, 0, 0, 5))); DoubleAnimation secondStopAnim = new DoubleAnimation(0.02, 0.96,new Duration(new TimeSpan(0, 0, 0, 5))); DoubleAnimation thirdStopAnim = new DoubleAnimation(0.03, 0.97,new Duration(new TimeSpan(0, 0, 0, 5))); DoubleAnimation fourthStopAnim = new DoubleAnimation(0.04, 0.98,new Duration(new TimeSpan(0, 0, 0, 5))); DoubleAnimation fifthStopAnim = new DoubleAnimation(0.05, 0.99,new Duration(new TimeSpan(0, 0, 0, 5))); firstStopAnim.AutoReverse = true; secondStopAnim.AutoReverse = true; thirdStopAnim.AutoReverse = true; fourthStopAnim.AutoReverse = true; fifthStopAnim.AutoReverse = true; firstStopAnim.BeginTime = new TimeSpan(0); secondStopAnim.BeginTime = new TimeSpan(0); thirdStopAnim.BeginTime = new TimeSpan(0); fourthStopAnim.BeginTime = new TimeSpan(0); fifthStopAnim.BeginTime = new TimeSpan(0); firstStopAnim.EasingFunction = new CubicEase(); secondStopAnim.EasingFunction = new CubicEase(); thirdStopAnim.EasingFunction = new CubicEase(); fourthStopAnim.EasingFunction = new CubicEase(); fifthStopAnim.EasingFunction = new CubicEase();這裏咱們加入5個點,而後設置默認屬性,以及範圍。默認屬性是本身主動返回相反方向,從0s開始,使用CubicEase動畫轉變。
一旦咱們建立動畫對象。咱們而後需要給內部5個漸變點以獨特的名稱,這樣咱們可以附加故事板對象控制他們的動畫。
String slotOneName = RandomName(); String slotTwoName = RandomName(); String slotThreeName = RandomName(); String slotFourName = RandomName(); String slotFiveName = RandomName(); RegisterName(slotOneName, gradientStops[1]); RegisterName(slotTwoName, gradientStops[2]); RegisterName(slotThreeName, gradientStops[3]); RegisterName(slotFourName, gradientStops[4]); RegisterName(slotFiveName, gradientStops[5]);函數「RandomName」是用戶加入的函數,放在繪製矩形方法以後。
你需要給每個名稱一個隨機名,這樣你可以重用矩形繪製方法。假設你嘗試重用已經被分配給以前顏色點的名稱,矩形函數將終止,但是你不會獲得阻止應用程序的異常。而是獲得黑色窗體,沒有不論什麼動畫。所以確保你的點名稱惟一是很是重要的,但是沒有混亂到你給出不可用的屬性名。
我在這裏使用的函數使用了隨機和一個GUID結合的方式,沒有危急的字符。
爲了在你的代碼中定義它。在MainWindow類中,矩形函數以後加入例如如下代碼:
private string RandomName() { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const int nameLen = 8; var random = new Random(); string temp = Guid.NewGuid().ToString(). Replace("-", String.Empty); temp = Regex.Replace(temp, @"[\d-]", string.Empty).ToUpper(); return new string(Enumerable.Repeat(chars, nameLen).Select (s => s[random.Next(s.Length)]).ToArray()) + temp; }隨機名稱設置好之後,咱們而後開始在矩形函數中設置漸變更畫。
下一件事是映射咱們剛建立的隨機屬性名,附加漸變點到故事板。
咱們使用WPF故事板類的靜態屬性來匹配,而後建立故事板局部對象,加入每個動畫到子集合。
Storyboard.SetTargetName(firstStopAnim, slotOneName); Storyboard.SetTargetProperty(firstStopAnim,new PropertyPath(GradientStop.OffsetProperty)); Storyboard.SetTargetName(secondStopAnim, slotTwoName); Storyboard.SetTargetProperty(secondStopAnim,new PropertyPath(GradientStop.OffsetProperty)); Storyboard.SetTargetName(thirdStopAnim, slotThreeName); Storyboard.SetTargetProperty(thirdStopAnim,new PropertyPath(GradientStop.OffsetProperty)); Storyboard.SetTargetName(fourthStopAnim, slotFourName); Storyboard.SetTargetProperty(fourthStopAnim,new PropertyPath(GradientStop.OffsetProperty)); Storyboard.SetTargetName(fifthStopAnim, slotFiveName); Storyboard.SetTargetProperty(fifthStopAnim,new PropertyPath(GradientStop.OffsetProperty)); Storyboard gradientAnimation = new Storyboard { RepeatBehavior = RepeatBehavior.Forever }; gradientAnimation.Children.Add(firstStopAnim); gradientAnimation.Children.Add(secondStopAnim); gradientAnimation.Children.Add(thirdStopAnim); gradientAnimation.Children.Add(fourthStopAnim); gradientAnimation.Children.Add(fifthStopAnim);而後緊接着加入例如如下夢幻般的代碼,放置在矩形方法末尾,在設置矩形left和top以後:
gradientAnimation.Begin(this);假設一切正常進行。按下F5你會看到3D條左右來回移動。
AnimationTimeInSeconds是你想讓故事板從矩形左側到右側執行的時間。這不包括返回時間。僅僅是動畫一圈的時間。 BarBaseRedLevel, BarBaseGreenLevel,和BarBaseBlueLevel被用來設置條的基色。設置這些可以用來改變條的整體顏色。
BarDescriptor barOne = new BarDescriptor { RectangleX = 0, RectangleY = 0, RectangleWidth = 800, RectangleHeight = 600, AnimationTimeInSeconds = 5, BarBaseRedLevel = 0, BarBaseGreenLevel = 0.5f, BarBaseBlueLevel = 0, GradientStartX = 0, GradientStartY = 0.5f, GradientEndX = 1, GradientEndY = 0.5f };而後改動「CreateRectangle」方法使得參數被用在需要的地方。
改動漸變點集的建立,讓它看起來例如如下:
GradientStopCollection gradientStops = new GradientStopCollection { new GradientStop(Color.FromScRgb(0.5f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 0.0), new GradientStop(Color.FromScRgb(0.0f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 0.01), new GradientStop(Color.FromScRgb(0.5f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 0.02), new GradientStop(Color.FromScRgb(1.0f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 0.03), new GradientStop(Color.FromScRgb(0.5f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 0.04), new GradientStop(Color.FromScRgb(0.0f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 0.05), new GradientStop(Color.FromScRgb(0.5f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 1.0), };而後。改動你建立線性漸變筆刷的行,看起來例如如下:
LinearGradientBrush gradientBrush = new LinearGradientBrush(gradientStops,new Point(inputParameters.GradientStartX, inputParameters.GradientStartY),new Point(inputParameters.GradientEndX,inputParameters.GradientEndY));假設一切順利,你應該有一個綠色條左右移動,和以前相比有輕微漸變:
現在需要作的就是把剩餘的條加入上去,建立不少其它「BarDescriptor」對象,將它們傳送到矩形建立方法例如如下:
BarDescriptor barOne = new BarDescriptor { RectangleX = 0, RectangleY = 0, RectangleWidth = 800, RectangleHeight = 600, AnimationTimeInSeconds = 5, BarBaseRedLevel = 0, BarBaseGreenLevel = 0.5f, BarBaseBlueLevel = 0, GradientStartX = 0, GradientStartY = 0.5f, GradientEndX = 1, GradientEndY = 0.5f }; BarDescriptor barTwo = new BarDescriptor { RectangleX = 0, RectangleY = 0, RectangleWidth = 800, RectangleHeight = 600, AnimationTimeInSeconds = 4, BarBaseRedLevel = 0, BarBaseGreenLevel = 0.5f, BarBaseBlueLevel = 0, GradientStartX = 1, GradientStartY = 0, GradientEndX = 0, GradientEndY = 1 }; BarDescriptor barThree = new BarDescriptor { RectangleX = 0, RectangleY = 0, RectangleWidth = 800, RectangleHeight = 600, AnimationTimeInSeconds = 3, BarBaseRedLevel = 0, BarBaseGreenLevel = 0.5f, BarBaseBlueLevel = 0, GradientStartX = 0, GradientStartY = 0, GradientEndX = 1, GradientEndY = 1 }; BarDescriptor barFour = new BarDescriptor { RectangleX = 0, RectangleY = 0, RectangleWidth = 800, RectangleHeight = 600, AnimationTimeInSeconds = 6, BarBaseRedLevel = 0, BarBaseGreenLevel = 0.5f, BarBaseBlueLevel = 0, GradientStartX = 0.5f, GradientStartY = 0, GradientEndX = 0.5f, GradientEndY = 1 }; CreateRectangleAnimatedRectangle(barOne); CreateRectangleAnimatedRectangle(barTwo); CreateRectangleAnimatedRectangle(barThree); CreateRectangleAnimatedRectangle(barFour);本文中開頭用的圖片就是四個條相互覆蓋的產品,贊成透明度相互結合。更改時間和更改速度有一樣效果。因此不一樣條移動速度不同。
僅僅是要記住,爲了能夠正常執行,你必須在中心有5個漸變,集合中有5個點。
using System; using System.Linq; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; namespace WpfAnimationTest { public partial class MainWindow { private Rectangle _testRect; public MainWindow() { InitializeComponent(); Loaded += MainWindowLoaded; } private void MainWindowLoaded(object sender, RoutedEventArgs e) { BarDescriptor barOne = new BarDescriptor { RectangleX = 0, RectangleY = 0, RectangleWidth = 800, RectangleHeight = 600, AnimationTimeInSeconds = 5, BarBaseRedLevel = 0, BarBaseGreenLevel = 0.5f, BarBaseBlueLevel = 0, GradientStartX = 0, GradientStartY = 0.5f, GradientEndX = 1, GradientEndY = 0.5f }; BarDescriptor barTwo = new BarDescriptor { RectangleX = 0, RectangleY = 0, RectangleWidth = 800, RectangleHeight = 600, AnimationTimeInSeconds = 4, BarBaseRedLevel = 0, BarBaseGreenLevel = 0.5f, BarBaseBlueLevel = 0, GradientStartX = 1, GradientStartY = 0, GradientEndX = 0, GradientEndY = 1 }; BarDescriptor barThree = new BarDescriptor { RectangleX = 0, RectangleY = 0, RectangleWidth = 800, RectangleHeight = 600, AnimationTimeInSeconds = 3, BarBaseRedLevel = 0, BarBaseGreenLevel = 0.5f, BarBaseBlueLevel = 0, GradientStartX = 0, GradientStartY = 0, GradientEndX = 1, GradientEndY = 1 }; BarDescriptor barFour = new BarDescriptor { RectangleX = 0, RectangleY = 0, RectangleWidth = 800, RectangleHeight = 600, AnimationTimeInSeconds = 6, BarBaseRedLevel = 0, BarBaseGreenLevel = 0.5f, BarBaseBlueLevel = 0, GradientStartX = 0.5f, GradientStartY = 0, GradientEndX = 0.5f, GradientEndY = 1 }; CreateRectangleAnimatedRectangle(barOne); CreateRectangleAnimatedRectangle(barTwo); CreateRectangleAnimatedRectangle(barThree); CreateRectangleAnimatedRectangle(barFour); } private void CreateRectangleAnimatedRectangle(BarDescriptor inputParameters) { DoubleAnimation firstStopAnim =new DoubleAnimation(0.01, 0.95,new Duration(new TimeSpan(0, 0, 0, 5))); DoubleAnimation secondStopAnim = new DoubleAnimation(0.02, 0.96,new Duration(new TimeSpan(0, 0, 0, 5))); DoubleAnimation thirdStopAnim = new DoubleAnimation(0.03, 0.97,new Duration(new TimeSpan(0, 0, 0, 5))); DoubleAnimation fourthStopAnim = new DoubleAnimation(0.04, 0.98,new Duration(new TimeSpan(0, 0, 0, 5))); DoubleAnimation fifthStopAnim = new DoubleAnimation(0.05, 0.99,new Duration(new TimeSpan(0, 0, 0, 5))); firstStopAnim.AutoReverse = true; secondStopAnim.AutoReverse = true; thirdStopAnim.AutoReverse = true; fourthStopAnim.AutoReverse = true; fifthStopAnim.AutoReverse = true; firstStopAnim.BeginTime = new TimeSpan(0); secondStopAnim.BeginTime = new TimeSpan(0); thirdStopAnim.BeginTime = new TimeSpan(0); fourthStopAnim.BeginTime = new TimeSpan(0); fifthStopAnim.BeginTime = new TimeSpan(0); firstStopAnim.EasingFunction = new CubicEase(); secondStopAnim.EasingFunction = new CubicEase(); thirdStopAnim.EasingFunction = new CubicEase(); fourthStopAnim.EasingFunction = new CubicEase(); fifthStopAnim.EasingFunction = new CubicEase(); GradientStopCollection gradientStops = new GradientStopCollection { new GradientStop(Color.FromScRgb(0.5f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 0.0), new GradientStop(Color.FromScRgb(0.0f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 0.01), new GradientStop(Color.FromScRgb(0.5f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 0.02), new GradientStop(Color.FromScRgb(1.0f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 0.03), new GradientStop(Color.FromScRgb(0.5f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 0.04), new GradientStop(Color.FromScRgb(0.0f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 0.05), new GradientStop(Color.FromScRgb(0.5f,inputParameters.BarBaseRedLevel,inputParameters.BarBaseGreenLevel,inputParameters.BarBaseBlueLevel), 1.0), }; String slotOneName = RandomName(); String slotTwoName = RandomName(); String slotThreeName = RandomName(); String slotFourName = RandomName(); String slotFiveName = RandomName(); RegisterName(slotOneName, gradientStops[1]); RegisterName(slotTwoName, gradientStops[2]); RegisterName(slotThreeName, gradientStops[3]); RegisterName(slotFourName, gradientStops[4]); RegisterName(slotFiveName, gradientStops[5]); LinearGradientBrush gradientBrush = new LinearGradientBrush(gradientStops,new Point(inputParameters.GradientStartX, inputParameters.GradientStartY),new Point(inputParameters.GradientEndX,inputParameters.GradientEndY)); Storyboard.SetTargetName(firstStopAnim, slotOneName); Storyboard.SetTargetProperty(firstStopAnim,new PropertyPath(GradientStop.OffsetProperty)); Storyboard.SetTargetName(secondStopAnim, slotTwoName); Storyboard.SetTargetProperty(secondStopAnim,new PropertyPath(GradientStop.OffsetProperty)); Storyboard.SetTargetName(thirdStopAnim, slotThreeName); Storyboard.SetTargetProperty(thirdStopAnim,new PropertyPath(GradientStop.OffsetProperty)); Storyboard.SetTargetName(fourthStopAnim, slotFourName); Storyboard.SetTargetProperty(fourthStopAnim,new PropertyPath(GradientStop.OffsetProperty)); Storyboard.SetTargetName(fifthStopAnim, slotFiveName); Storyboard.SetTargetProperty(fifthStopAnim,new PropertyPath(GradientStop.OffsetProperty)); Storyboard gradientAnimation = new Storyboard { RepeatBehavior = RepeatBehavior.Forever }; gradientAnimation.Children.Add(firstStopAnim); gradientAnimation.Children.Add(secondStopAnim); gradientAnimation.Children.Add(thirdStopAnim); gradientAnimation.Children.Add(fourthStopAnim); gradientAnimation.Children.Add(fifthStopAnim); _testRect = new Rectangle { Width = inputParameters.RectangleWidth, Height = inputParameters.RectangleHeight, Stroke = Brushes.White, StrokeThickness = 1, Fill=gradientBrush }; Root.Children.Add(_testRect); Canvas.SetLeft(_testRect, inputParameters.RectangleX); Canvas.SetTop(_testRect, inputParameters.RectangleY); gradientAnimation.Begin(this); } private string RandomName() { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const int nameLen = 8; var random = new Random(); string temp = Guid.NewGuid().ToString(). Replace("-", String.Empty); temp = Regex.Replace(temp, @"[\d-]", string.Empty).ToUpper(); return new string(Enumerable.Repeat(chars, nameLen).Select (s => s[random.Next(s.Length)]).ToArray()) + temp; } } }