Click here to Skip to main content
15,880,651 members
Articles / Programming Languages / C#
Article

Windows Phone 7 Animations — Alternatives, Performance

3 Feb 2011CPOL13 min read 49.4K   6   4
The article discusses alternative ways how to organize WP7 animations – Storyboard-driven, timer animations and per-frame animations. Both programming techniques and performance comparisons are presented.

This article is in the Product Showcase section for our sponsors at CodeProject. These articles are intended to provide you with information on products and services that we consider useful and of value to developers.

The article discusses alternative ways how to organize WP7 animations – Storyboard-driven, timer animations and per-frame animations. Both programming techniques and performance comparisons are presented.

Introduction

The new technologies — such as WPF/Silverlight — consume CPU power for the sake of easier programming and entertaining the user. These things are usually hidden under the cover and many programmers find hard to quantify them.

When I wrote my last article — one of the topics concerned the efficiency of the animations used in the ProgressBar control. We shall now investigate this topic further and try to use collected material to get deeper understanding of WP7 animations. We demonstrate how to perform Storyboard animations both in XAML and C# code. Then we show how to perform the same animations using classic timer (DispatcherTimer) and also in the render thread callbacks – so called “per-frame” animations. At the end we compare how these methods perform.

I wrote also a benchmark application used to get numbers referenced in the article. In the ideal world the reader could simply install the application and give it a run to convince himself. However, due to WP7 restrictions, you have to use the source code and build the application yourself. If you wish to go this way, you can install Resco MobileForms Toolkit — Windows Phone 7 Edition and related sample application – the ProgressBar benchmarks occupy one of the pages. (Yes, self-advertising. Sorry for that.)

Prerequisites

The target audience is a C# programmer with a reading knowledge of Silverlight. At the very minimum the reader should understand basic Silverlight controls and layout.

To run the sample codes you need to have installed Windows Phone Developer Tools.

What We Are Going To Do

All of you know the nice animation when the WP7 loads — five small dots running across the screen. Technically speaking it is ProgressBar control with IsIndeterminate property set to true.

Many of you might have noticed Jeff Wilcox's article warning against the use of standard ProgressBar (http://www.jeff.wilcox.name/2010/08/performanceprogressbar/) as it is based on animating five slider controls with terrible performance impact. Instead, Jeff offered a more efficient alternative ProgressBar template (known under the name PerformanceProgressBar) that is based on animating five small rectangles.

We shall start by porting PerformanceProgressBar template into the code. We’ll show that the resulting source code is smaller and simpler, while the control itself is a bit more efficient.

So far we talked about Storyboard animations – whether in XAML or C# code. What it means is that we set up the animation (i.e. define the Storyboard) and let the system run it. (i.e. call Storyboard.Begin().)

Think a bit what it means. Say we wanted a rectangle running across the screen. We have to:

  • Create Storyboard object
  • Take the rectangle object and its RenderTransform.X property (position in X direction)
  • Tell the Storyboard to change this property from the value 0 to the value (say) 300 within 2 seconds
  • Call Storyboard.Begin()

That’s at least the basic idea. In the reality we use more complex setup — more objects, more properties, nonlinear movement. It takes a while to learn special language that is used in XAML to define the animations. Of course, you can use equivalent C# code. It’s not more difficult, just a bit less common. The result will be slightly faster code (no runtime XAML analysis involved) with identical UX.

If you are an experienced programmer you must feel it a kind of overhead as the same thing could be done easily in the code without learning a new strange language. All you need is to set up a timer (trivial) and control the RenderTransform.X property in the timer callback. Seems to be easier (and we’ll show that it is easier), so what’s the purpose of these Storyboards?

Well, there are two reasons:

  • One is to enable cooperation with a designer who can’t use C#, but can eventually learn this special Storyboard language used in XAML.
  • And the second one is that Storyboards appear to get special treatment under WP7. They simply run faster than your timer: The animations are nicer, the CPU load is higher.

WP7 has one more possibility to organize animations – so-called per-frame callback. The idea is that the OS calls your code after each frame is rendered. We’ll show that from the programmer point of view this method is quite similar to the timer animations and — as far the performance is concerned – it stands in between Storyboard and timer-based animations.

In the following we’ll show how to implement ProgressBar using various animation constructs and we’ll analyze their performance impact.

Technical remark:

I saw blogs explaining that Storyboard runs on the GPU without negative impact on the CPU. Well, this is not true: Storyboard runs on the high priority render thread which in turn runs on the CPU as any other thread. The principal difference against your C# code is that you can’t programmatically access the render thread; you even have no means to create any high-priority code at all.

Setup of the Performance Tests

Actually we used the same setup as described in my previous article; hence we just present a brief summary.

The UI contained a ProgressBar control. Once the progress bar animation was activated, we started a background thread running this loop:

C#
Count  = 0;
while (!_done) {
	count++;
	int  cnt = 100 + count % 100;  // a  number with 3 digits
	cnt.ToString();
}

After 10-15 seconds the test was stopped and the number count/sec recorded.

We repeated the same test with various ProgressBar implementations and compared the results.

Reliability of the test results

The results of repeated trials showed the variability of up to 5%. To minimize this variance we report average numbers after excluding extreme fluctuations.

Let’s discuss how reliable are the presented numbers.
First the obvious arguments:

  • The time measurement: WP7 can measure only milliseconds. This error is negligible given the fact that the tests took 10+ seconds. Just forget this argument.
  • Variable test duration: Unimportant because we compared normalized numbers. (count/sec) Forget.

Other random effects include GC, system overhead. Garbage collecting could be done prior to each test to minimize this effect. (We haven’t done it.)

However, the most important factor is easily overlooked. The animations are nonlinear, i.e. each cycle contains the movement period and the rest period. (Other nonlinearities are less important by an order of magnitude.)

It is obvious that while the ProgressBar animation is at rest (dots hidden), the CPU load is smaller than when the dots are moving. We even constructed an experiment that proved that the performance increases when the animation cycle gets larger.

The basic problem is that the standard length of one ProgressBar animation cycle (Duration=4.4 sec) is comparable to the duration of a typical test run (10-15 sec).

To test this hypothesis we run special series of tests with minimal rest period. (We used Duration=3.3. Unfortunately you cannot test this with Resco IndeterminateProgressBar control as it requires Duration>=4.0.) The results:

  • The fluctuations decreased three-fold.
  • The relative differences between various animation implementations were preserved.

Finally the hardware impact. Presented numbers come from Htc HD7 device. We briefly run the tests on another device and the results seemed to be very similar. My bet is that the conclusions are general. I just cannot imagine how hardware could cause substantial differences. Better GPU? Well, the bottleneck seems to be CPU and this is standardized.

ProgressBar layout

PerformanceProgressBar

The simplified control layout is as follows (5 small transparent rectangles):

C#
<Grid><Border>
	<Grid>
		<Rectangle  Height="4" Width="4" x:Name="R1"  
                       Opacity="0" CacheMode="BitmapCache">
			<Rectangle.RenderTransform>
				<TranslateTransform  x:Name="R1TT"/>
			</Rectangle.RenderTransform>
		</Rectangle>
		//  .... Identical definitions for rectangles R2..R5 
                   // (with transforms R2TT..R5TT)
	</Grid>
</Border></Grid>

The above code is taken from Jeff Wilcox PerformanceProgressBar template.

Equivalent C# code

This is an excerpt from the source code of IndeterminateProgressBar class (part of Resco MobileForms Toolkit — Windows Phone 7 Edition) that constructs the control layout. The differences against the PerformanceProgressBar:

  • A bit simpler layout (3 containers are replaced by just one)
  • No named controls (savings at the load time)
  • No XAML (even larger savings)

The MakeLayout() method is called in the Loaded event handler.

C#
// 5 rectangles composing the  progress bar
private Rectangle R1, R2, R3,  R4, R5;
private void MakeLayout()
	{
		Grid g = new Grid() { HorizontalAlignment = HorizontalAlignment.Left  };
		R1 = MakeDot(); g.Children.Add(R1);
		R2 = MakeDot(); g.Children.Add(R2);
		R3 = MakeDot(); g.Children.Add(R3);
		R4 = MakeDot(); g.Children.Add(R4);
		R5 = MakeDot(); g.Children.Add(R5);
		this.Content = g;
	}
	
private Rectangle MakeDot()
	{
		Rectangle r = new Rectangle() { Height = 4, Width =  4, 
                       IsHitTestVisible = false, Opacity = 1, 
		Visibility=Visibility.Collapsed,  CacheMode = new BitmapCache() };
		// Color can be changed by setting Foreground 
                   // (this binding has no performance impact)
		Binding b = new Binding("Foreground") {  Source = this }
		r.SetBinding(Rectangle.FillProperty, b);
		// Rectangle will be subject of translation, hence we 
                   // prepare corresp. transform
		r.RenderTransform = new TranslateTransform();
		return r;
	}
 
private void Show(bool bShow)
	{
		Visibility vis = bShow ? Visibility.Visible : Visibility.Collapsed;
		R1.Visibility = vis;
		R2.Visibility = vis;
		R3.Visibility = vis;
		R4.Visibility = vis;
		R5.Visibility = vis;
	}

Setting up the animation

Constructing the Storyboard Animation in XAML

The simplified animation used for PerformanceProgressBar:

C#
<Storyboard  RepeatBehavior="Forever" Duration="00:00:04.4">
	<DoubleAnimationUsingKeyFrames  BeginTime="00:00:00.0" 
	Storyboard.TargetProperty="X"  Storyboard.TargetName="R1TT">
		<LinearDoubleKeyFrame  KeyTime="00:00:00.0" Value="0.1"/>
		<EasingDoubleKeyFrame  KeyTime="00:00:00.5" Value="33.1"
			EasingFunction="{StaticResource  ProgressBarEaseOut}/>
		<LinearDoubleKeyFrame  KeyTime="00:00:02.0" Value="66.1"/>
		<EasingDoubleKeyFrame  KeyTime="00:00:02.5" Value="100.1"
			EasingFunction="{StaticResource ProgressBarEaseIn}/>
	</DoubleAnimationUsingKeyFrames>
	<DoubleAnimationUsingKeyFrames  BeginTime="00:00:00.0" 
		Storyboard.TargetProperty="Opacity"  Storyboard.TargetName="R1">
		<DiscreteDoubleKeyFrame  KeyTime="0" Value="1"/>
		<DiscreteDoubleKeyFrame KeyTime="00:00:02.5"  Value="0"/>
	</DoubleAnimationUsingKeyFrames>
	// .... Identical animations for R2 (delayed by 0.2  sec) … R5 (delayed by 0.8 sec)
</Storyboard>

Basically each rectangle is displayed for 2.5 sec while moving left-to-right.

Second rectangle is delayed by 0.2 sec, 3rd by 0.4 sec etc. so that the whole movement takes 3.3 sec.

Then there is 1.1 sec pause and the whole cycle repeats.

The easing functions describing the nonlinearity of the movement are defined in the resources:

C#
<ExponentialEase  EasingMode="EaseOut" Exponent="1" x:Key="ProgressBarEaseOut"/>
<ExponentialEase  EasingMode="EaseIn" Exponent="1" x:Key="ProgressBarEaseIn"/>

Notice that in this case XAML is not sufficient. Take this line:

C#
<LinearDoubleKeyFrame KeyTime="00:00:02.0"  Value="66.1"/>

Above code says "Move R1 rectangle (R1TT is its TranslateTransform) to the distance 66.1 at the time 2.0 sec."

A nonsense, of course. The author actually wanted to say "Move to 66% of the control width".

As SVL does not accept relative numbers, the PerformanceProgressBar template is wrapped in an extra control (RelativeAnimatingContentControl) whose single reason of being is to re-compute relative numbers to absolute equivalents.

(If you want to know the details: It reacts to SizeChanged event and scans all VisualStateManager animations looking for double values of the shape *.1; such values are then treated as relative portions of the control width.)

Constructing the Storyboard animation in code

Below is an excerpt from the source code of IndeterminateProgressBar class containing the MakeStoryboard() method. While the Xaml code appears to be shorter, it is not true – we simply omitted most of it.

As far the performance is concerned:

  • C# solution loads faster. (No need to translate XAML. No need to resolve object names. No need to re-compute animations to fit the control width.)
  • Run-time performance should be equivalent. In fact C# code might have small advantage because of simpler layout.
C#
// Easing functions used for  the left/right ends. (The movement in the
      // center part is linear.)
private ExponentialEase  ProgressBarEaseOut =
    new ExponentialEase() { EasingMode = EasingMode.EaseOut,  Exponent = 1 };
private ExponentialEase  ProgressBarEaseIn =
    new ExponentialEase() { EasingMode = EasingMode.EaseIn,  Exponent = 1 };

// Key time instants 0, 0.5,  2, and 2.5 sec
private KeyTime kt1 = KeyTime.FromTimeSpan(TimeSpan.Zero);
private KeyTime kt2 = KeyTime.FromTimeSpan(new  TimeSpan(0, 0, 0, 0, 500));
private KeyTime kt3 = KeyTime.FromTimeSpan(new  TimeSpan(0, 0, 0, 2, 0));
private KeyTime kt4 = KeyTime.FromTimeSpan(new  TimeSpan(0, 0, 0, 2, 500));

private Timeline  CreateTranslateAnimation(TimeSpan beginTime, UIElement target)
{
    DoubleAnimationUsingKeyFrames animation =
        new DoubleAnimationUsingKeyFrames()  { BeginTime = beginTime };
    Storyboard.SetTargetProperty(animation, new PropertyPath("X"));
    Storyboard.SetTarget(animation,  target.RenderTransform);

    Thickness p = Padding;
    double len = Width - p.Left - p.Right;
    animation.KeyFrames.Add(new LinearDoubleKeyFrame()
        { KeyTime = kt1, Value = p.Left });
    animation.KeyFrames.Add(new EasingDoubleKeyFrame()
        { KeyTime = kt2, Value = p.Left+len*0.33,
                         EasingFunction = ProgressBarEaseOut });
    animation.KeyFrames.Add(new LinearDoubleKeyFrame()
        { KeyTime = kt3, Value = p.Left+len*0.66 });
    animation.KeyFrames.Add(new EasingDoubleKeyFrame()
        { KeyTime = kt4, Value = p.Left+len,
                         EasingFunction = ProgressBarEaseIn });
    return animation;
}

private Timeline  CreateVisibilityAnimation(TimeSpan beginTime, UIElement target)
{
    DoubleAnimationUsingKeyFrames animation =
        new DoubleAnimationUsingKeyFrames()  { BeginTime = beginTime };
    Storyboard.SetTarget(animation, target);
    Storyboard.SetTargetProperty(animation, new PropertyPath("Opacity"));
    animation.KeyFrames.Add( new DiscreteDoubleKeyFrame()  { KeyTime = kt1,
                   Value = 1 } );
    animation.KeyFrames.Add( new DiscreteDoubleKeyFrame()  { KeyTime = kt4,
                   Value = 0 } );
    return animation;
}

private Storyboard MakeStoryboard()
{
    Storyboard sb = new Storyboard() { RepeatBehavior =
                   RepeatBehavior.Forever  };
    sb.Duration = new Duration(new TimeSpan(10000 *  m_duration));

    // Animation BeginTime's for individual dots.
    // (Dots  use the same animation, but shifted in time.)
    TimeSpan t1 = TimeSpan.Zero;
    TimeSpan t2 = new TimeSpan(0, 0, 0, 0, 200);
    TimeSpan t3 = new TimeSpan(0, 0, 0, 0, 400);
    TimeSpan t4 = new TimeSpan(0, 0, 0, 0, 600);
    TimeSpan t5 = new TimeSpan(0, 0, 0, 0, 800);

    // Animations for the left-to-right movement
    sb.Children.Add(CreateTranslateAnimation(t1, R1));
    sb.Children.Add(CreateTranslateAnimation(t2, R2));
    sb.Children.Add(CreateTranslateAnimation(t3, R3));
    sb.Children.Add(CreateTranslateAnimation(t4, R4));
    sb.Children.Add(CreateTranslateAnimation(t5, R5));

    // Animations specifying the time interval when the  dots are visible.
    sb.Children.Add(CreateVisibilityAnimation(t1, R1));
    sb.Children.Add(CreateVisibilityAnimation(t2, R2));
    sb.Children.Add(CreateVisibilityAnimation(t3, R3));
    sb.Children.Add(CreateVisibilityAnimation(t4, R4));
    sb.Children.Add(CreateVisibilityAnimation(t5, R5));
    return sb;
}

Constructing Custom Animation in Code

Below is the code that handles one animation step.
We additionally need a way to keep animation running — this will be shown later.

C#
private int m_startTime; // When the animation started
private EasingFunctionBase ProgressBarEase = new MyEase(); //see below
 
// Animation step
void UpdateProgressBar(object sender, EventArgs e)
{
	const int dt = 150;
	int t = (Environment.TickCount - m_startTime) % m_duration;
	HandleRectangle(R1, t);
	HandleRectangle(R2, t - dt);
	HandleRectangle(R3, t - 2*dt);
	HandleRectangle(R4, t - 3*dt);
	HandleRectangle(R5, t - 4*dt);
}
 
// Adapts the rectangle position and visibility as a function of time
private void HandleRectangle( Rectangle r, int time)
{
	if (time < 0 || time > 2500)
	{
		r.Opacity = 0.01; // rectangle hidden after 2.5 sec
	}	
	else
	{
		TranslateTransform tt = (TranslateTransform)r.RenderTransform;
		
		double normalizedTime = ProgressBarEase.Ease(time / 2500.0);
		Thickness p = Padding;
		double len = Width - p.Left - p.Right;
		double pos = p.Left + len * normalizedTime;
		double dif = Math.Abs(pos - tt.X);
		
		if (dif > m_sensitivity) {
			r.Opacity = 1;
			tt.X = pos;
		}
	}
}

Movement Description

The progress bar control is nice because the dots move in a nice way. Storyboard animations use so-called easing functions for this purpose.

An easing function transforms the time progress. It receives normalized time (time between 0 and 1) and returns transformed normalized time. In other words the easing function defines the time flow.

Silverlight supports plenty of easing functions and you are free to define your own ones. Here is an example that models the PerformanceProgressBar behavior.

Recall first the XAML definition of the dot animation:

C#
<DoubleAnimationUsingKeyFrames>
	<LinearDoubleKeyFrame  KeyTime="00:00:00.0" Value="0.1"/>
	<EasingDoubleKeyFrame  KeyTime="00:00:00.5" Value="33.1" 
		EasingFunction="{StaticResource  ProgressBarEaseOut}/>
	<LinearDoubleKeyFrame  KeyTime="00:00:02.0" Value="66.1"/>
	<EasingDoubleKeyFrame  KeyTime="00:00:02.5" Value="100.1"  
		EasingFunction="{StaticResource ProgressBarEaseIn}/>
</DoubleAnimationUsingKeyFrames>

What it means for normalized time? The time 2.5 sec corresponds to 1, 2.0 sec corresponds to 0.8 etc.

Below is corresponding easing function. This function is used by HandleRectangle() method. (Of course, we could compute the time progress ourselves, but why?)

C#
class MyEase : EasingFunctionBase
{
	// Models the behavior from PerformanceProgressBar
	private ExponentialEase ProgressBarEaseOut = new ExponentialEase() 
		{ EasingMode = EasingMode.EaseOut, Exponent = 1 };
	private ExponentialEase ProgressBarEaseIn = new ExponentialEase()
		{ EasingMode = EasingMode.EaseIn, Exponent = 1 };
	double t1, t2;
	
	public MyEase()
	{
		t1 = ProgressBarEaseOut.Ease(0.2);
		t2 = ProgressBarEaseIn.Ease(0.8);
	}
	
	// Transform Normalized time (progress) of the animation, 
          // which is a value from 0 through 1.
	protected override double EaseInCore(double normalizedTime)
	{
		if (normalizedTime <= 0.2)
			return ProgressBarEaseOut.Ease(normalizedTime);
		else
		if (normalizedTime > 0.8)
			return ProgressBarEaseIn.Ease(normalizedTime);
		else
			return t1 + (t2 - t1) * (normalizedTime - 0.2) / (0.8-0.2);
	}
}

Four Ways to Do aAnimations

Let’s summarize what we can do so far:

  1. Construct the control layout both in code and XAML.
  2. Construct the Storyboard both in code and XAML.
  3. Construct one step of equivalent custom animation.

Let’s supply the missing parts so that we can compare different ways of performing animations.

XAML Animations

The animation is defined as follows:

C#
<VisualStateManager.VisualStateGroups>
	<VisualStateGroup  x:Name="CommonStates">
		<VisualState  x:Name="Determinate"/>
		<VisualState  x:Name="Indeterminate">
			<Storyboard  .../>
		</VisualState>
	</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

The Control author has to issue following call to start the animation:
VisualStateManager.GoToState("Indeterminate")

In turn the VisualStateManager starts respective animation.

Storyboard Animation Run from the Code

For example this method could be used to start/stop control animation:

C#
private Storyboard m_animation  = null;
 
private void StartStopStoryboardAnimation( bool bStart )
{
	if  (bStart)  {
		m_animation  = MakeStoryboard();
		m_animation.Begin();
	}
	else if  (m_animation != null)  {
		m_animation.Stop();
		m_animation  = null;
	}
}

Custom Animation - Timer Based

We use DispatcherTimer, i.e. a timer running on the UI thread. This timer is used to keep the animation running.
Here is the method used to start/stop control animation:

C#
private DispatcherTimer m_timer = null;
private int m_startTime;
 
private void StartStopTimerAnimation(bool bStart)
{
	if (bStart) 
	{
		if (m_timer == null) 
		{
			m_startTime = Environment.TickCount;
			UpdateProgressBar(null, null);
			m_timer = new DispatcherTimer();
			m_timer.Interval = new TimeSpan(0, 0, 0, 0, 30); // 33 fps
			m_timer.Tick += UpdateProgressBar;
			m_timer.Start();
		}
	}
	else if (m_timer != null) 
	{
		m_timer.Stop();
		m_timer.Tick -= UpdateProgressBar;
		m_timer = null;
	}
}

Note that we could alternatively use System.Threading.Timer running on a non-UI thread and then use Dispatcher.BeginInvoke() to update the UI. However, as the single purpose of the timer is to periodically update the UI, this attitude would just add on complexity without any gains.

Custom Per-Frame Animation

From the .NET Framework Class Library documentation:

  • CompositionTarget class represents the display surface of a SVL application.
  • CompositionTarget.Rendering event occurs just before the objects in the composition tree are rendered.

It means we can use the Rendering event to perform UI changes once per frame.
This method is used to start/stop control animation:

C#
private int m_startTime;
 
private void StartStopPerFrameAnimation(bool bStart)
{
	if (bStart) 
	{
		m_startTime = Environment.TickCount;
		CompositionTarget.Rendering += UpdateProgressBar;
	}
	else
		CompositionTarget.Rendering -= UpdateProgressBar;
}

As you see the timer- and per-frame animations effectively use the same code to perform the animation; they only differ in the way the process is started.

Running Animation from Code

Below is the last missing piece - the trigger property used to start/stop animations.
We omitted the definition of the Method property; it lets you select the animation method from an enumeration of available methods. The interested reader will supply it easily.

C#
public bool IsActive {
	get { return (bool)GetValue(IsActiveProperty); }
	set { SetValue(IsActiveProperty, value); }
}
 
public static readonly DependencyProperty IsActiveProperty =
	 DependencyProperty.Register
		("IsInfinite", typeof(bool), typeof(IndeterminateProgressBar), 
		new PropertyMetadata(false,IsActiveChanged) );
 
private static void IsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
	IndeterminateProgressBar bar = (IndeterminateProgressBar)d;
	
	if (bar.Method == IndeterminateProgressBarMethod.Storyboard)
		bar.StartStopStoryboardAnimation(bar.IsActive);
	else 
	if (bar.Method == IndeterminateProgressBarMethod.Timer)
		bar.StartStopTimerAnimation(bar.IsActive);
	else 
	if (bar.Method == IndeterminateProgressBarMethod.PerFrame)
		bar.StartStopPerFrameAnimation(bar.IsActive);
	
	bar.Show(bar.IsActive);
}

Results

So far we have described different ways to perform animations. In the following we shall run various tests to compare these methods. However, certain things can be expected a priori.

XAML solution uses "nice animations" (simple animations of double values). Such animations will run on the render thread and the graphical operations should be performed on the GPU. As the render thread has high priority, one can expect fluent animations with non-negligible CPU impact.

Storyboard animations performed from the code might have similar performance, or even better - as the control layout is simpler.
Timer-based animations are run on the UI thread (lower priority than the render thread). One could intuitively expect jerkier behavior and smaller CPU impact.

Per-frame animations might be positioned in between storyboard and timer-based animations. Hard to do a more detailed prediction.
To get the real numbers we wrote dedicated test code. You can try it yourself if you install the Resco MobileForms Toolkit - Windows Phone 7 Edition – it is one of the pages of the sample application.

The UI is shown in the figure below. (The numbers shown are from the emulator; don’t take them seriously.) Each checkbox starts different test scenario:

  • No progress bar: Means running background computation without any UI activity.
  • Standard ProgressBar: Means standard WP7 ProgressBar with IsIndeterminate=true.
  • Performance ProgressBar stands for original Jeff Wilcox template with IsIndeterminate=true.

Next three checkboxes are bound to the methods offered by IndeterminateProgressBar that were discussed above:

  • Storyboard animations from code
  • DispatcherTimer animations
  • Per-frame animations

The final case (“Custom Progress”) refers to a kind of minimalistic implementation – a small circle changing its opacity each 600 msec.
When you press a checkbox, corresponding test starts. When you uncheck the checkbox, the test terminates and the value count/sec is displayed. You can thus compare different methods.

You can even test several animations running at the same time. In this case the actual numbers are unimportant. But you can verify another thing – Storyboard animations (both C# and Xaml) are more fluent, while the remaining animations show jerky behavior. This clearly proves that Storyboard animations have higher priority.

screenshot.jpg

Here is the typical outcome expressed as a percentage of the maximal speed:

No ProgressBar

100%

Standard ProgressBar

38%

PerformanceProgressBar (Xaml animations)

51%

Storyboard animations from code

54%

DispatcherTimer animations, 33 fps

81%

Per-frame animations

68%

Custom (Simple animations, 2 fps)

96%

Do we need to formulate any conclusion? I think the numbers say it all.

About the Author

Jan Slodicka. Programming for over 30 years. Covered several desktop platforms and programming languages. Since 2003 working for Resco on mobile technologies – Palm OS, Windows Mobile, now Windows Phone 7.

You can contact me at jano at resco.net or through Resco forums.

Resco MobileForms Toolkit - Windows Phone 7 Edition can be downloaded from http://www.resco.net/developer/mobilelighttoolkit. The Toolkit contains a set of useful controls that simplify Windows Phone 7 programming. Besides WP7, there is also Windows Mobile, Android and iOS edition.

Resco is a company with a long tradition of mobile programming covering many platforms and both end-user applications and developer tools.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Marketing Resco
Slovakia Slovakia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionNon-DoubleAnimation tests Pin
Tendoors27-Jul-11 17:55
Tendoors27-Jul-11 17:55 
AnswerRe: Non-DoubleAnimation tests Pin
janslodicka27-Jul-11 22:19
janslodicka27-Jul-11 22:19 
GeneralCode to test this Pin
mydvision14-Mar-11 23:25
mydvision14-Mar-11 23:25 
GeneralRe: Code to test this Pin
janslodicka15-Mar-11 1:35
janslodicka15-Mar-11 1:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.