Suppose you want to write a little program that rotates some text using the CompositionTarget.Rendering event. You can pace this animation either by the rate that video hardware refreshes the display, or by clock time. Because each refresh of the video display is called a frame, these two methods of pacing animation are referred to as frame-based and time-based.
Here’s a little program that shows the difference. The content area of the XAML file has two TextBlock elements with RotateTransform objects set to their RenderTransform properties, and a Button:
Example 1. Silverlight Project: FrameBasedVsTimeBased File: MainPage.xaml (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Frame-Based" FontSize="{StaticResource PhoneFontSizeLarge}" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5 0.5"> <TextBlock.RenderTransform> <RotateTransform x:Name="rotate1" /> </TextBlock.RenderTransform> </TextBlock>
<TextBlock Grid.Row="1" Text="Time-Based" FontSize="{StaticResource PhoneFontSizeLarge}" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5 0.5"> <TextBlock.RenderTransform> <RotateTransform x:Name="rotate2" /> </TextBlock.RenderTransform> </TextBlock>
<Button Grid.Row="2" Content="Hang for 5 seconds" HorizontalAlignment="Center" Click="OnButtonClick" /> </Grid>
|
The code-behind file saves the current time in a field and then attaches a handler for the CompositionTarget.Rendering event. This event handler is then called in synchronization with the video frame rate.
Example 2. Silverlight Project: FrameBasedVsTimeBased File: MainPage.xaml.cs (excerpt)
public partial class MainPage : PhoneApplicationPage { DateTime startTime; public MainPage() { InitializeComponent();
startTime = DateTime.Now; CompositionTarget.Rendering += OnCompositionTargetRendering; }
void OnCompositionTargetRendering(object sender, EventArgs args) { // Frame-based rotate1.Angle = (rotate1.Angle + 0.2) % 360;
// Time-based TimeSpan elapsedTime = DateTime.Now - startTime; rotate2.Angle = (elapsedTime.TotalMinutes * 360) % 360; }
void OnButtonClick(object sender, RoutedEventArgs args) { Thread.Sleep(5000); } }
|
The rotation angle for the first TextBlock
is increased by 0.2° every frame. I calculated this by knowing that the
phone display is refreshed at 30 frames per second. Multiply 30 frames
per second by 60 seconds per minute by 0.2° and you get 360°.
The rotation angle for the second TextBlock is calculated based on the elapsed time. The TimeSpan structure has a convenient TotalMinutes property and this is multiplied by 360 for the total number of degrees to rotate the text.
Both work, and they work approximately the same:
But if your phone is anything like my phone, you’ll see that the frame-based animation lags a little behind the time-based animation, and the lag progressively gets larger and larger. Why?
The calculation for the frame-based animation assumes that the CompositionTarget.Rendering
handler is called at the rate of 30 times per second. However, the
phone I’m using for this book has a video refresh rate closer to 27
frames per second—about 27.35, to be more precise.
That’s one problem with frame-based animation: It’s dependent on the actual hardware. Your mileage may vary.
Here’s another difference: Suppose the program suddenly needs to perform some job that hogs the processor. The FrameBasedVsTimeBased program simulates such a job with a Button that hangs the thread for 5 seconds. Both animations grind to a halt during this time because the calls to the CompositionTarget.Rendering
handler are not asynchronous. When the revolutions start up again, the
frame-based animation continues from where it left off; the time-based
animation jumps ahead to where it would have been had the delay never
occurred.
Whether you prefer one
approach to the other ultimately depends on the application. Sometimes
you really do need a frame-based animation. But if you ever need to use
an animation to pace the hands of a clock or something similar, a
time-based animation is essential; frame-based animations are just too unpredictable for the job.
The Silverlight
animation library is all time-based. You specify what change you want
over a particular period of time, and the Silverlight animation classes
handle the rest.