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代码如下:
Storyboard.TargetName="MyRectangle"
Storyboard.TargetProperty="Width"
From="100" To="200" Duration="0:0:1" />
将它翻译成C#代码则如下:
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的容器,它包含了若干的简单动画来完成一个复杂动画。
参考以下代码:
<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是如何工作的。
参考以下代码:
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);
};
其中:
));
定义了一个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,如此重复.也许我们会编写如下的代码:
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).
参考下面的代码:
{
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的类型或可以与之转换的类型.
这样我们的代码就演化如下:
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();语句.
更多的,请参见Windows SDK "Storyboard Overview"
WPF中的动画的更多相关文章
- WPF中的动画——(三)时间线(TimeLine)
WPF中的动画——(三)时间线(TimeLine) 时间线(TimeLine)表示时间段. 它提供的属性可以让控制该时间段的长度.开始时间.重复次数.该时间段内时间进度的快慢等等.在WPF中内置了如下 ...
- 【WPF学习笔记】[转]周银辉之WPF中的动画 && 晓风影天之wpf动画——new PropertyPath属性链
(一)WPF中的动画 动画无疑是WPF中最吸引人的特色之一,其可以像Flash一样平滑地播放并与程序逻辑进行很好的交互.这里我们讨论一下故事板. 在WPF中我们采用Storyboard(故事板)的方式 ...
- [转]WPF中的动画
WPF中的动画 周银辉 动画无疑是WP ...
- (转载)WPF中的动画——(一)基本概念
http://www.cnblogs.com/TianFang/p/4050845.html WPF的一个特点就是支持动画,我们可以非常容易的实现漂亮大方的界面.首先,我们来复习一下动画的基本概念.计 ...
- WPF中的动画——(一)基本概念
WPF的一个特点就是支持动画,我们可以非常容易的实现漂亮大方的界面.首先,我们来复习一下动画的基本概念.计算机中的动画一般是定格动画,也称之为逐帧动画,它通过每帧不同的图像连续播放,从而欺骗眼和脑产生 ...
- WPF中的动画——(五)关键帧动画
与 From/To/By 动画类似,关键帧动画以也可以以动画形式显示目标属性值. 和From/To/By 动画不同的是, From/To/By 动画只能控制在两个状态之间变化,而关键帧动画则可以在多个 ...
- WPF中的动画——(六)演示图板
前面所介绍的都是单一的动画,它只能修改单一属性.有的时候,我们需要将一组动画一起进行,对于一个按钮,我们可能有如下需求: 选择该按钮时,该按钮增大并更改颜色. 单击该按钮时,该按钮缩小并恢复其原始大小 ...
- WPF中的动画——(五)路径动画
路径动画是一种专门用于将对象按照指定的Path移动的动画,虽然我们也可以通过控制动画的旋转和偏移实现对象的移动,但路径动画更专业,它的实现更加简洁明了. 路径动画中最常用的是MatrixAnimati ...
- WPF中的动画——(二)From/To/By 动画
我们所实现的的动画中,很大一部分是让一个属性在起始值和结束值之间变化,例如,我在前文中实现的改变宽度的动画: var widthAnimation = new DoubleAnimation() ...
随机推荐
- Java设计模式应用——工厂模式
工厂模式有三种:简单工厂.工厂方法.抽象工厂 一. 抽象工厂 1. 一个可以生产多种产品的工厂: 2. 不改变工厂无法生产新的产品. package com.coshaho.learn.factory ...
- Google、亚马逊、微软 、阿里巴巴开源软件一览
Google.亚马逊.微软 .阿里巴巴开源软件一览 大公司为什么要发布开源项目?一是开源能够帮助他人更快地开发软件,促进世界创新,主要是社会价值层面的考虑.二是开源能够倒逼工程师写出更好的代码.三是开 ...
- 基于GIT的管理
常用命令 git init : 初始化仓库git add 文件名 :把文件添加到暂存区git commit -m "操作记录" : 提交到仓库,设置相关操作的记录 git stat ...
- 如何在Linux环境下通过uwgsi部署Python服务
部署python程序时常常会遇到同一台服务器上2.x和3.x共存的情况,不同应用需要使用不用的python版本,使用virtualenv创建虚拟环境能很好地解决这一问题. 首先,需要在服务器上安装vi ...
- 如何写出一个让人很难发现的bug?
程序员的日常三件事:写bug.改bug.背锅.连程序员都自我调侃道,为什么每天都在加班?因为我的眼里常含bug. 那么如何写出一个让(坑)人(王)很(之)难(王)发现的bug呢? - 1 -新手开发+ ...
- Python Web学习笔记之并发和并行的区别和实现
你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行.你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发.你吃饭吃到一半,电话来了,你一边打 ...
- Java随机获取32位密码且必须包含大小写字母、数字和特殊字符,四种的任意三种
Java随机获取32位密码且必须包含大小写字母.数字和特殊字符,四种的任意三种 Java随机获取32位密码且必须包含大小写字母.数字和特殊字符,四种的任意三种,代码如下: import java.ut ...
- dom4j解析xml报"文档中根元素后面的标记格式必须正确"
今天,在写个批量启动报盘机的自动化应用,为了简化起见,将配置信息存储在xml中,格式如下: <?xml version="1.0" encoding="UTF-8& ...
- this逃逸
首先,什么是this逃逸? this逃逸是指类构造函数在返回实例之前,线程便持有该对象的引用. 常发生于在构造函数中启动线程或注册监听器. eg: public class ThisEscape { ...
- C++ tinyXml直接解析XML字符串
转载:http://www.cnblogs.com/1024Planet/p/4401929.html <?xml version=\"1.0\" encoding=\&qu ...