动画和定时器是紧密相关的,下面的三个例子既可以说是定时器,也可以说是动画。
编码使用定时器
编码方式使用定时器,最简单的就是使用 System.Windows.Threading 命名空间的 DispatcherTimer 类。虽然也可以用 System.Timers.Timer,但是实现就会复杂多了,不推荐使用System.Timers.Timer,原因如下:
在每个 Dispatcher (管理线程工作项队列的服务)循环的顶端重新计算 DispatcherTimer。 这样 DispatcherTimer 不能保证会正好在时间间隔发生时执行计时器,但能够保证不会在时间间隔发生之前执行计时器。 这是因为 DispatcherTimer 操作与其他操作一样被放置到 Dispatcher 队列中。 何时执行 DispatcherTimer 操作取决于队列中的其他作业及其优先级。
如果 System.Timers.Timer 用于 WPF/Silverlight 应用程序,则值得注意的是 System.Timers.Timer 运行于不同于用户界面 (UI) 线程的其他线程上。 为了访问用户界面 (UI) 线程上的对象,需要使用 Invoke 或 BeginInvoke 将操作发布到用户界面 (UI) 线程的 Dispatcher 上。
使用 DispatcherTimer 而不是使用 System.Timers.Timer 的原因是 DispatcherTimer 与 Dispatcher(管理线程工作项队列的服务) 运行于相同的线程,并且可以在 DispatcherTimer 上设置 DispatcherPriority。
使用 DispatcherTimer 的例子
XAML 文件
<Grid x:Name="LayoutRoot" Background="White"> <TextBlock Loaded="StartTimer" x:Name="myTextBlock" /> Grid>
代码文件
public void StartTimer(object o, RoutedEventArgs sender) { System.Windows.Threading.DispatcherTimer myDispatcherTimer = new System.Windows.Threading.DispatcherTimer(); myDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 100); // 100 Milliseconds myDispatcherTimer.Tick += new EventHandler(Each_Tick); myDispatcherTimer.Start(); } // A variable to count with. int i = 0; // Raised every 100 miliseconds while the DispatcherTimer is active. public void Each_Tick(object o, EventArgs sender) { myTextBlock.Text = "Count up: " + i++.ToString(); }
使用故事版来做的定时器
我们在 Storyboard 的 Completed 事件中再次把Storyboard 起来: myTimer.Begin(); 这就相当于一个定时器。
XAML文件
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="MySilverlight3Study_Animation3.MainPage" Width="180" Height="120"> <UserControl.Resources> <Storyboard x:Name="myTimer" Duration="00:00:01" Completed="myTimer_Completed" /> UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> Grid.RowDefinitions> <Button x:Name="btn" Height="36" Margin="20,5" Content="开始" Grid.Row="1" Click="Button_Click"/> <TextBlock x:Name="txt" Grid.Row="0" Height="40" Width="60" Text="0" TextWrapping="Wrap" Foreground="#FFA72222" FontSize="26.667" FontFamily="Comic Sans MS" FontWeight="Bold" TextAlignment="Center" LineHeight="9.333"/> Grid> UserControl>
代码文件
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; namespace MySilverlight3Study_Animation3 { public partial class MainPage : UserControl { public MainPage() { // 为初始化变量所必需 InitializeComponent(); } private bool isStop = true; private void Button_Click(object sender, System.Windows.RoutedEventArgs e) { if(isStop) { btn.Content = "暂停"; myTimer.Begin(); } else { btn.Content = "继续"; myTimer.Stop(); } isStop = !isStop; } private int i = 0; private void myTimer_Completed(object sender, EventArgs e) { i++; txt.Text = string.Format("{0}",i); myTimer.Begin(); } } }
用 CompositionTarget.Rendering 来做动画和定时器
除了之前提到的几种动画方式,还有一种只能使用代码创建的基于帧的动画方式。需要做的全部工作是响应静态的 CompositionTarget.Rendering 事件,触发该事件是为了为每帧获取内容。这是一种非常低级的方法,除非使用标准的基于属性的动画模型不能满足需要(例如,构建一个简单的游戏、创建一个基于物理的动画,或者构建粒子效果模型(如火焰、雪以及气泡)),否则不会希望使用这种方法。
构建基于帧的动画的基本技术很容易。只需要简单地为静态的CompositionTarget.Rendering事件关联事件处理程序。一旦关联了事件处理程序,Silverlight就会开始不断地调用这个事件处理程序(只要渲染代码执行得足够快,每秒将会调用60次)。
下面是一个简单的演示代码:
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; namespace MySilverlight3Study_Animation3 { public partial class MainPage : UserControl { public MainPage() { // 为初始化变量所必需 InitializeComponent(); System.Windows.Media.CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering); } void CompositionTarget_Rendering(object sender, EventArgs e) { txt.Text = DateTime.Now.ToString(); } } }
Xaml 文件
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="MySilverlight3Study_Animation3.MainPage" Width="180" Height="120"> <TextBlock x:Name="txt" Text="1" Margin="20" Foreground="Red" TextAlignment="Center" /> UserControl>
一般游戏,为了性能,都是使用 CompositionTarget.Rendering 事件来做的。而不是之前的2种方式。
参考资料:
SilverLight Timers, what to use?
http://advertboy.wordpress.com/2007/08/11/silverlight-timers-what-to-use/
在Silverlight中使用定时器(Timer)
http://blog.youkuaiyun.com/SilverlightShanghai/archive/2007/09/02/1768874.aspx
Silverlight 2 手把手(之六) 使用故事版实现定时器
http://blogs.msdn.com/jijia/archive/2008/04/30/silverlight2-timer-storyboard.aspx
Silverlight 2 手把手(之五) 编程实现定时器
http://blogs.msdn.com/jijia/archive/2008/04/29/programming-timer.aspx
How to: Create a Timer
http://msdn.microsoft.com/en-us/library/cc189084(VS.95).aspx
Make a Silverlight Timer (Silverlight 2)
http://blogs.msdn.com/silverlight_sdk/archive/2008/03/27/make-a-silverlight-timer-silverlight-2.aspx
21.4.5 基于帧的动画
http://book.51cto.com/art/200908/145560.htm
Silverlight: How to use CompositionTarget.Rendering event to synchronize discrete and non-discrete animations
CompositionTarget.Rendering事件
http://blog.etvalley.com/index.php/archives/tag/compositiontargetrendering
Silverlight制作逐帧动画 v2 - part1
http://www.cnblogs.com/nasa/archive/2009/09/11/imageBrush-Animate.html
Silverlight制作逐帧动画 v2 - part2
http://www.cnblogs.com/nasa/archive/2009/09/12/imageBrush-Animate-part2.html
Silverlight制作逐帧动画 v2 - part3
http://www.cnblogs.com/nasa/archive/2009/09/13/imageBrush-Animate-part3.html
Blend基础-动画
http://www.cnblogs.com/nasa/archive/2009/11/03/Expression_Blend_Essentials_Animation.html