(一)WPF中的动画

动画无疑是WPF中最吸引人的特色之一,其可以像Flash一样平滑地播放并与程序逻辑进行很好的交互。这里我们讨论一下故事板。

在WPF中我们采用Storyboard(故事板)的方式来编写动画,为了对Storyboard有个大概的印象,你可以粘贴以下代码到XamlPad来查看效果:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"WindowTitle="Storyboards Example"><StackPanel Margin="20"><Rectangle Name="MyRectangle"Width="100"Height="100"><Rectangle.Fill><SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" /></Rectangle.Fill><Rectangle.Triggers><EventTrigger RoutedEvent="Page.Loaded"><BeginStoryboard><Storyboard RepeatBehavior="Forever" AutoReverse="True"><DoubleAnimation Storyboard.TargetName="MyRectangle"Storyboard.TargetProperty="Width"From="100" To="200" Duration="0:0:1" />              </Storyboard></BeginStoryboard></EventTrigger></Rectangle.Triggers></Rectangle> </StackPanel>
</Page>

在介绍Storyboard之前应该先了解Animation
Animation提供一种简单的“渐变”动画,我们为一个Animation指定开始值和一个结束值,并指定由开始值到达结束值所需的时间,便可形成一个简单的动画。比如我们指定长方形的宽度由100变化到200,所需时间为1秒,很容易想像这样的动画是什么样的,而它对应的Xaml代码如下:

            <DoubleAnimation Storyboard.TargetName="MyRectangle"Storyboard.TargetProperty="Width"From="100" To="200" Duration="0:0:1" />

将它翻译成C#代码则如下:

            DoubleAnimation myDoubleAnimation = new DoubleAnimation();myDoubleAnimation.From = 100;myDoubleAnimation.To = 200;myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Rectangle.WidthProperty));

代码里我们定义了一个DoubleAnimation,并指定了它的开始值和结束值以及它由开始值到达结束值所需的时间。至于后面两句,它们是用来将Aniamtion与指定的对象和指定的属性相关联,等会我们将介绍。
注意到,这里我们使用的是DoubleAnimation,因为我们所要变化的是数值。那么如果我们要变化颜色是不是就用ColorAnimation了呢,对,其实出了这些之外还有PointAnimation等等,并且你可以实现IAnimatable接口来实现自定义版本的Animation。关于这些你可以参见System.Windows.MediaAniamtion名字空间.

但值得注意的是并非每个属性都能够使用Animation,它必须满足以下条件:
1,它必须是Dependency Property
2,它所在类必须继承于DependencyObject,必须实现了IAnimatable接口.
3,必须有类型一致的Animation Type(即Color类型使用ColorAniamtion,Point类型使用PointAnimation等)

一个简单的Animation定义了一个简单的动画,很容易想到的是,如果若干个Animation同时作用于一个对象,那么这个对象不就可以表现复杂的动画了吗,对,这就是Storyboard

Storyboard可以看做是Animation的容器,它包含了若干的简单动画来完成一个复杂动画。
参考以下代码:

<!-- This example shows how to animate with a storyboard.-->
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"WindowTitle="Storyboards Example"><StackPanel Margin="20"><Rectangle Name="MyRectangle"Width="100"Height="100"><Rectangle.Fill><SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" /></Rectangle.Fill><Rectangle.Triggers><EventTrigger RoutedEvent="Page.Loaded"><BeginStoryboard><Storyboard RepeatBehavior="Forever" AutoReverse="True"><DoubleAnimation Storyboard.TargetName="MyRectangle"Storyboard.TargetProperty="Width"From="100" To="200" Duration="0:0:1" />    <ColorAnimation Storyboard.TargetName="MySolidColorBrush"Storyboard.TargetProperty="Color"From="Blue" To="Red" Duration="0:0:1" />            </Storyboard></BeginStoryboard></EventTrigger></Rectangle.Triggers></Rectangle> </StackPanel>
</Page>

这里我们的Storyboard定义了DoubleAnimation来变化矩形的宽度,并定义了ColorAnimation来变化矩形的颜色。

至此,你已经可以编写绚丽的WPF动画了,并推荐你下载Expression Blend来制作WPF动画.

但你会发现使用XAML标记的方式来编写动画虽然很简单,但缺乏了C#等程序设计语言的灵活性,比如我们的矩形动画中矩形的宽度是由后台逻辑计算出来的变量值,我们的动画将如何编写呢,这时我更喜欢使用C#的方式来编写动画,虽然这所需的代码量更大.
以下重点介绍如何用C#编写动画,并且这更助于你理解Storyboard是如何工作的。

参考以下代码:

            this.Name = "PageMain";myRectangle.Name = "MyRectangle";  NameScope.SetNameScope(this, new NameScope());                      this.RegisterName(myRectangle.Name, myRectangle);DoubleAnimation myDoubleAnimation = new DoubleAnimation();myDoubleAnimation.From = 100;myDoubleAnimation.To = 200;myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Rectangle.WidthProperty));Storyboard myStoryboard = new Storyboard();myStoryboard.Children.Add(myDoubleAnimation);this.Loaded += delegate(object sender, MouseEventArgs e){myStoryboard.Begin(this);};

其中:

DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = 100;
            myDoubleAnimation.To = 200;
            myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
定义了一个DoubleAniamtion,并指定了它的开始值和结束值以及所需的时间.
Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);设置myDoubleAniamtion的作用对象是"myRectangle",注意到传入的第二个参数是一个字符串myRectangle.Name,那么我们的程序怎么知道"myRectangle"这个字符串就是指我们的矩形对象myRectangle呢,这里存在一个名称与对象的映射,即我们的"myRectangle"映射到矩形对象myRectangle,为了构造这个映射我们涉及到了NameScope(名字域)这个概念.
            NameScope.SetNameScope(this, new NameScope());                      
            this.RegisterName(myRectangle.Name, myRectangle);
上面的代码中,this设置了一个名字域,myRectagle向这个名字域注册了自己的名字,这样我们的程序就可以通过this的名字域来查找到myRectangle与"myRectangle"之间的映射关系了,关于NameScope可以参见MSDN WPF Namescopes主题.
为了让myDoubleAnimation知道它所作用的属性是谁,我们使用Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Rectangle.WidthProperty));语句来将Aniamtion与属性关联起来,其中PropertyPath中指定要作用的对象所对应的DependencyProperty.
然后我们将定义好的myDoubleAniamtion添加到myStoryboard的Children中去.最后就可以通过调用Storyboard的Begin(FrameworkElement)方法来开始我们的动画.

Begin方法的另一个重载形式是public void Begin (FrameworkContentElement containingObject,bool isControllable),第二个参数表明我们的storyboard是否是可控的,如果可控的话,我们可以像控制播放器一样控制来控制storyboard,关于控制Storyboard请参考Storyboard类中的Pause,Seek等方法.

至此也许我们会认为这些知识足以应付简单的动画了,现在让我们一起设计一个简单的动画,也许会发现些问题.

假设我们的界面中存在一个Button对象button1,我们设计一个简单的动画让它在窗口中的x坐标从0连续变化到100,然后在从100变化到0,如此重复.也许我们会编写如下的代码:

            this.button1.Name = "button1";this.Name = "window1";NameScope.SetNameScope(this, new NameScope());this.RegisterName(this.button1.Name, this.button1);DoubleAnimation xAnimation = new DoubleAnimation();xAnimation.From = 0;xAnimation.To = 100;xAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));Storyboard story = new Storyboard();story.AutoReverse = true;story.RepeatBehavior = RepeatBehavior.Forever;story.Children.Add(xAnimation);Storyboard.SetTargetName(xAnimation, this.button1.Name);Storyboard.SetTargetProperty(xAnimation, ???);

但当我们编写到Storyboard.SetTargetProperty(xAnimation, ???);时发现似乎不知道将我们的xAniamtion关联到哪个属性.似乎Button中没有用来控制X坐标的DependencyProperty.但通过研究后发现(你可以通过ExpressionBlend自动生成的XAML代码来发现这些信息),如果我们将button1的RenderTransform设置为TranslateTransform,然后可以通过TranslateTransform的XProperty属性来更改button1的X坐标.注意到,我们并不是像以前一样直接关联到Button的某个属性(比如先前的WidthProperty),而是通过其RenderTransformProperty属性的XProperty来间接关联的,这中方式叫做"属性链"(PropertyChain).
参考下面的代码:

            DependencyProperty[] propertyChain = new DependencyProperty[]{Button.RenderTransformProperty,TranslateTransform.XProperty};Storyboard.SetTargetProperty(xAnimation, new PropertyPath("(0).(1)", propertyChain));

为了构造PropertyChain,我们先定义一个DependencyProperty的数组,注意数组的元素是怎么来的,它按照属性链的"链条"关系依次书写,直到到达我们最终要修改的属性,(由于我们是通过将RenderTransformProperty设置为TranslateTransform类型,所以第二个元素是TranslateTransform.XProperty),简单地说就是(类型1.属性1,类型2.属性2,....类型n.属性n),其中类型i是属性i-1的类型或可以与之转换的类型.
这样我们的代码就演化如下:

            this.button1.RenderTransform = new TranslateTransform();this.button1.Name = "button1";this.Name = "window1";NameScope.SetNameScope(this, new NameScope());this.RegisterName(this.button1.Name, this.button1);DoubleAnimation xAnimation = new DoubleAnimation();xAnimation.From = 0;xAnimation.To = 100;xAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));DependencyProperty[] propertyChain = new DependencyProperty[]{Button.RenderTransformProperty,TranslateTransform.XProperty};Storyboard story = new Storyboard();story.AutoReverse = true;story.RepeatBehavior = RepeatBehavior.Forever;story.Children.Add(xAnimation);Storyboard.SetTargetName(xAnimation, this.button1.Name);Storyboard.SetTargetProperty(xAnimation, new PropertyPath("(0).(1)", propertyChain));story.Begin(this);

注意:如果你收到关于PropertyChain的运行时错误或动画没有效果,那么你应该初始化button的RenderTransform属性,所以我们添加了this.button1.RenderTransform = new TranslateTransform();语句.

=======================================================================================================================

二)wpf动画——new PropertyPath属性链

在wpf中我们常用storyboard故事板装载很多的动画处理Animation,我们需要用Storyboard.SetTarget设置操作的对象,需要用Storyboard.SetTargetProperty设置操作对象的操作属性PropertyPath,本例将说明一种操作属性PropertyPath的便利方法:

1.新建一个wpf应用程序,简单修改一下xaml展示如下:

<Window x:Class="WpfApplication48.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="MainWindow" Height="350" Width="525"><Grid><Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" /></Grid>
</Window>

2.后台cs修改如下(效果:点击button,button的横坐标x由12到300,播放过程动画):

    /// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void button1_Click(object sender, RoutedEventArgs e){this.button1.RenderTransform = new TranslateTransform();Storyboard sb = new Storyboard();DoubleAnimation da = new DoubleAnimation();da.From = 12;da.To = 300;da.Duration = TimeSpan.FromSeconds(3);sb.Children.Add(da);DependencyProperty[] propertyChain = new DependencyProperty[]{Button.RenderTransformProperty,TranslateTransform.XProperty};Storyboard.SetTarget(da, this.button1);Storyboard.SetTargetProperty(da, new PropertyPath("(0).(1)", propertyChain));sb.Completed += new EventHandler((object sender1, EventArgs e1) => { MessageBox.Show("completed"); });sb.Begin();}}

一般我们在写到Storyboard.SetTargetProperty时遇到new PropertyPath,

如果是简单的属性,例如Button.WidthProperty,我们可以直接new PropertyPath(Button.WidthProperty)达到目的,
但如果你发现你需要操作到的属性无法在Button中直接'.'出来,就需要用到上例用到的属性链方法:

首先定义一个属性链:

            DependencyProperty[] propertyChain = new DependencyProperty[]{Button.RenderTransformProperty,TranslateTransform.XProperty};

属性链的写法,定义一个DependencyProperty属性的数组,该数组中的元素均是Property属性,且按照从属关系先后排列,例如上例中,我们需要先将button的RenderTransform设置为TranslateTransform,然后通过TranslateTransform的XProperty来更改button的x坐标,

当然,别忘了初始化button的RenderTransform属性= new TranslateTransform(),否则动画将没有效果。

以上未经博主同意转载,敬请原谅。

转载于:https://www.cnblogs.com/Owen-ET/p/5981660.html

【WPF学习笔记】[转]周银辉之WPF中的动画 晓风影天之wpf动画——new PropertyPath属性链...相关推荐

  1. WPF学习笔记-第二周【基本笔刷】

    书接上回,这一次,讲的是WPF中的基本笔刷,由于是菜鸟,就不多说了,继续帖示例代码:) 第一部份 代码 第二章 基本笔刷 第一个 示例 VaryTheBackgroud P38  1     #reg ...

  2. WPF学习笔记(数据绑定篇3)

    接上回的<WPF学习笔记(数据绑定篇2)>,继续 BindValidation 此示例演示了: 如何使用错误模板: 使用样式显示错误信息: 如何在校验发生异常时执行回调: 首先,你可以看见 ...

  3. WPF学习笔记(7):DataGrid中数字自定义格式显示

    WPF学习笔记(7):DataGrid中数字自定义格式显示 原文:WPF学习笔记(7):DataGrid中数字自定义格式显示 DataGrid中数据显示如下图,数据格式比较杂乱.希望达到以下要求:(1 ...

  4. 几何光学学习笔记(31)- 6.6 光学系统中光能损失的计算

    几何光学学习笔记(31)- 6.6 光学系统中光能损失的计算 6.6 光学系统中光能损失的计算 1. 透射面的反射损失 2. 镀金属层的反射面的吸收损失 3. 透射光学材料内部的吸收损失 4.总述 6 ...

  5. Tensorflow学习笔记6:解决tensorflow训练过程中GPU未调用问题

    Tensorflow学习笔记6:解决tensorflow训练过程中GPU未调用问题 参考文章: (1)Tensorflow学习笔记6:解决tensorflow训练过程中GPU未调用问题 (2)http ...

  6. FreeRtos学习笔记(11)查找就绪任务中优先级最高任务原理刨析

    FreeRtos学习笔记(11)查找就绪任务中优先级最高任务原理刨析 怎么查找就绪任务中优先级最高的? tasks.c中声明了一个全局变量 uxTopReadyPriority,任务从其他状态进入就绪 ...

  7. C# 学习笔记(18)操作SQL Server 中

    C# 学习笔记(18)操作SQL Server 中 数据库基础操作 SQL语法可以参考 菜鸟教程 或者微软官方的SQL示例 注意SQL不区分大小写 查 1.基础查询 --最基础的查询语句, selec ...

  8. VSTO学习笔记(四)从SharePoint 2010中下载文件

    原文:VSTO学习笔记(四)从SharePoint 2010中下载文件 上一次我们开发了一个简单的64位COM加载项,虽然功能很简单,但是包括了开发一个64位COM加载项的大部分过程.本次我们来给CO ...

  9. Android学习笔记(四):在Activity中跳转--Intent的使用

    Android学习笔记(四):在Activity中跳转--Intent的使用 上篇,我们实战了一个很小的项目BMI,通过BMI这个项目,可以很好的理解Activity的程序结构,以方便后面高级API的 ...

最新文章

  1. Opencv定义感兴趣区域
  2. 干了10年软件工程师,我学到10个教训
  3. 用Tableau画3D模型之四(放弃篇)
  4. CENTOS7错误:Cannot find a valid baseurl for repo: base/7/x86_6
  5. 工业级光纤收发器的“附加属性“功能介绍
  6. VS2010中的路径设置
  7. mysql添加外键约束的两种方式(重要)
  8. 【转】MYSQL入门学习之七:MYSQL常用函数
  9. Json学习总结(4)——Json基础知识回顾
  10. [Google Guava]学习--新集合类型BiMap
  11. skimage 安装和子模块
  12. 电商数据抓取是什么意思?有什么作用?
  13. WPS Excel+windows批处理批量重排序文件夹
  14. 【web素材】16—激发你开发灵感的十大创意网站菜单示例效果
  15. Python自动化运维介绍
  16. RFID-MFRC522射频识别S50白卡
  17. *5-2 CCF 2014-12-3 集合竞价
  18. android指定sim卡拨号,使用双SIM卡设备中的指定SIM拨打电话
  19. 小米手机防盗nbsp;方法、安全及可…
  20. 还在埋头苦干?会构建个人品牌的人已在弯道超车

热门文章

  1. 如何保持连接_工高连城 | 连接器连接失效的原因有哪些
  2. Flash播放控件属性详解
  3. Django通过中间件实现登录验证demo
  4. 【Python练习题】程序5
  5. Python基础44(PyMySQL模块)
  6. SpringMVC日期类型转换问题处理方法归纳
  7. ServiceStack学习之一准备工作
  8. c语言数组指定位置插入和删除_Apache POI在指定位置插入表格
  9. Android studio 运行即打包keystore之build.gradle设置
  10. 比较精确的js倒计时实现