1. 程式人生 > >WPF 有趣的動畫效果

WPF 有趣的動畫效果

影響 你在 temp edev uid 組成 數據 第一個 升級

WPF 有趣的動畫效果

這一次我要呈上一個簡單的文章,關於給你的WPF apps加入美麗的光線動畫,可是我對動畫這東西可能有點入迷了。

實際上。我對動畫如此的入迷,以至於我最後做了之前從未打算做的東西,就是使用一些很實用的.NET代碼,漸變填充生成背景動畫。讓我先給你看一些終於效果吧。

技術分享
WPF和元素定位 然而。在我們開始之前。我們須要考慮一件事情。這件事讓我也有點原地轉圈的感覺。

似乎當你使用WPF創建不論什麽閉環形狀時,你不能設置它的X和Y坐標。好吧。至少你不能在一般的WPF窗口(像VS開箱即用的形狀)上。 這一點上,我要謝謝我的好朋友(以及WPF各種大神)Gavin Lanata。他幫我解釋說,假設要在代碼中以我想要的方式定位。就不得不將窗體的根布局從grid變為canvas。

這是非常令人沮喪的。如此簡單的東西(而且是大多開發者會考慮尋找的東西)在WPF中卻不被覺得是繪制形狀的要求。

我跑題了。如今我們什麽也做不了。

讓我們開始吧 打開Visual Studio,開始新的WPF應用程序項目。命名為WpfAnimationTest。

你能夠使用Blend。可是由於我們大多數要輸入代碼。Blend可能有點過度了。

一旦你的模板載入完成,請改動你的“MainWindow.xaml”文件,看起來像這樣。
<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項目,這裏我們畫的大部分用代碼實現。

使用這個記錄。你能夠輕易使用聲明的XAML,復制本文中的全部東西,可是會有大量反復漸變、漸變點和其它須要資源的東西。通過使用這裏的代碼方法,我們是用的不論什麽東西在超出範圍後都能夠處理掉;並且更重要的是。它是可重用代碼。


首先是一點兒理論

假設你了解過XAML,你將可能知道WPF中全部東西都能夠成為動畫。顏色,位置,大小。填充這些能夠使用時間線和故事板能夠非常easy變成動畫。 你使用很多可用動畫時間線類型中的一種創建你的動畫順序。通常新建對象。然後設置開始值、終止值,以及動畫執行時間長度。然後在將它們附加到故事板並啟動執行之前,附加這些動畫時間線到你想要它們控制的UI元素的屬性上。 然而。有件事我沒有意識到,一個彩色漸變點位置也能夠做成動畫。當你在WPF中創建顏色漸變時。你使用一系列對象“漸變點”創建了它們。 假設你以前使用過PhotoShop之類的圖像處理軟件,而且使用小方形顏色標記器在顏色應該改變的地方標記填充位置,你已經使用了相似的概念。

比如,假設你想要在中間使用從紅到藍顏色漸變,然後變綠,你可能在0%處創建紅色點。在50%創建藍色,100%處創建綠色。

WPF圖畫引擎然後在全部顏色間填充。這樣你就得到從一個顏色到下一個的平滑過渡。

在大多數WPF中大多數測量使用所謂的本地坐標系統。這意味著你的窗口上,可能寬度有比方800像素,從0%到100%範圍使用0到1來代表。設置漸變時,這可能意味著0像素在0.0或0%,400像素在0.5或50%,800像素在1.0或100%,全部你的顏色點位置都是這樣指定的。 我們試一些代碼吧 打開主要窗體XAML代碼。如果你已經如之前提到的改動了canvas,你應該加入例如以下代碼到MainWindow構造器中。
        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);
        }
你也能夠設置矩形全局的實心填充顏色。

然而。實心顏色有點無趣。

我們將改動成更加有趣的東西。

首先,讓我們通過將它在自身的函數中包裝起來,然後也創建數據對象傳送參數過去。我們將加入全部須要的參數到數據對象,而且我將解釋我們遇到的每一個對象。 加入新類到你的項目,命名為BarDescription。

輸入例如以下代碼:

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; }
    }
}
確保依照你的須要改動了命名空間。

然後,打開MainWindow.xaml.cs(或者你隨意命名的主窗體後臺代碼)。然後確保輸入一下代碼:
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”對象,並設置對應參數。 然而,如今如果你設置主窗體大小和我的同樣(800*600)。設置barOne屬性例如以下:
            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
            };
這樣會創建和主窗體相同大小的矩形。 加入漸變 為了使用普通C#代碼創建一個漸變色,你須要使用一個“LinearGradientBrush”對象和一個"GradientStopCollection"。漸變筆刷將被用來填充矩形背景,而且點集合將設置漸變過程的顏色。 我們的漸變中。也會使用透明度。透明度從0.0到1.0-0%到100%。設置為0%意味著不同看透它;它沒有透明度,而100%(1)則全然透明,顯示了它背後的一切。

透明度的設置同意你控制多少背景、多少顏色顯示出來。

在創建矩形方法內部的前面,加入例如以下的代碼創建你的顏色點:
            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
            };
這些都做好後,執行你的應用程序,你會得到: 技術分享
你應該可以直接看到不同透明度的影響。以及它導致填充圓柱形3D條外觀的效果。為了實現動畫。我們須要移動5個漸變點,組成漸變部分看起來像3D條。在上面的漸變點集中。這些值是5個值。位於兩個外部值之間,位置從0.01到0.05.
我們須要從左至右移動這些顏色點,並返回。這意味著我們須要下述動作:
  • 點1從0.01到0.95並返回;
  • 點2從0.02到0.96並返回;
  • 點3從0.03到0.97並返回。
  • 點4從0.04到0.98並返回;
  • 點5從0.05到0.99並返回。

我們通過創建5個雙值動畫對象達成效果。每一個分別匹配一個顏色點。加入下述代碼到矩形方法中。在創建漸變點之前:
            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條左右來回移動。 技術分享
之前,記得我簡要提到“BarDescriptor”對象的其它參數嗎?我們將充分使用它。 你已經知道。RectangleX, RectangleY, RegtangleWidth,和RectangleHeight指定位置和繪制矩形的大小。

AnimationTimeInSeconds是你想讓故事板從矩形左側到右側執行的時間。這不包括返回時間。僅僅是動畫一圈的時間。 BarBaseRedLevel, BarBaseGreenLevel,和BarBaseBlueLevel被用來設置條的基色。設置這些能夠用來改變條的總體顏色。

最後,GradientStartX, GradientStartY, GradientEndX,和GradientEndY設置漸變將遵從的直線路徑。這些值從0.0到1.0,代表X和Y方向的0%到100%。比如,假設設置0,0到1,1,你的3D條將從左上角到右下角,沿著對角方向動畫。設置0,0.5和1,0.5將使動畫沿著普通的從左到右。

改動barOne對象,讓它擁有下面值:
            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;
        }
    }
}


WPF 有趣的動畫效果