WPF 有趣的动画效果

WPF 有趣的动画效果

        这一次我要呈上一个简单的文章,关于给你的WPF apps添加漂亮的光线动画,但是我对动画这东西可能有点入迷了。
        实际上,我对动画如此的入迷,以至于我最后做了之前从未打算做的东西,就是使用一些非常有用的.NET代码,渐变填充生成背景动画。让我先给你看一些最终效果吧。
WPF 有趣的动画效果_第1张图片
WPF和元素定位
        然而,在我们开始之前,我们需要考虑一件事情。这件事让我也有点原地转圈的感觉。
        似乎当你使用WPF创建任何闭环形状时,你不能设置它的X和Y坐标。好吧,至少你不能在一般的WPF窗体(像VS开箱即用的形状)上。
        这一点上,我要谢谢我的好朋友(以及WPF各种大神)Gavin Lanata,他帮我解释说,如果要在代码中以我想要的方式定位,就不得不将窗口的根布局从grid变为canvas。这是很令人沮丧的,如此简单的东西(并且是大多开发人员会考虑寻找的东西)在WPF中却不被认为是绘制形状的要求。我跑题了,现在我们什么也做不了。
让我们开始吧
        打开Visual Studio,开始新的WPF应用程序项目,命名为WpfAnimationTest。你可以使用Blend,但是因为我们大多数要输入代码,Blend可能有点过度了。
        一旦你的模板加载完毕,请修改你的“MainWindow.xaml”文件,看起来像这样。

            
    
        你会看到,除了将背景变为黑色,我们改变了默认的grid为canvas,并且设置了窗体大小和标题。改变的也不多。不像大多说WPF/XAML项目,这里我们画的大部分用代码实现。
        使用这个记录,你可以轻易使用声明的XAML,复制本文中的所有东西,但是会有大量重复渐变、渐变点和其他需要资源的东西。通过使用这里的代码方法,我们是用的任何东西在超出范围后都可以处理掉;而且更重要的是,它是可重用代码。
首先是一点儿理论
        如果你了解过XAML,你将可能知道WPF中所有东西都可以成为动画。颜色,位置,大小,填充这些可以使用时间线和故事板可以很容易变成动画。
        你使用许多可用动画时间线类型中的一种创建你的动画顺序,通常新建对象,然后设置开始值、终止值,以及动画运行时间长度。然后在将它们附加到故事板并启动运行之前,附加这些动画时间线到你想要它们控制的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
            };
        这些都做好后,运行你的应用程序,你会得到:
WPF 有趣的动画效果_第2张图片
        你应该能够直接看到不同透明度的影响,以及它导致填充圆柱形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条左右来回移动。  
WPF 有趣的动画效果_第3张图片
        之前,记得我简要提到“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));
        如果一切顺利,你应该有一个绿色条左右移动,和之前相比有轻微渐变:
WPF 有趣的动画效果_第4张图片
        如果你看到上图,恭喜你。现在需要做的就是把剩余的条添加上去,创建更多“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;
        }
    }
}


你可能感兴趣的:(C#)