WPF replacement options for an animated gif or How to make a spinner?

Option 1 – Spin an image using a Storyboard

UPDATE: Check out this more recent post: A SpinningImage control in WPF

If your animation is just a single image that moves, such as a spinner, you can use a Storyboard to spin the single image.

Here is a spinner.png file (128×128) that I made really quickly in Paint.NET.

Spinner

  1. Create a default WPF Application project in visual studio.
  2. Add the spinner.png image to the project (or use your own image).
  3. Add a Storyboard to the resources.

Here is the Xaml.

<Window x:Class="SpinAnImage.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="300" Width="300">
    <Window.Resources>
        <Storyboard x:Key="Spin360" Storyboard.TargetName="Spinner" Storyboard.TargetProperty="RenderTransform.(RotateTransform.Angle)">
            <DoubleAnimation From="0" To="360" BeginTime="0:0:0" Duration="0:0:2" RepeatBehavior="Forever" />
        </Storyboard>
    </Window.Resources>
    <Grid>
        <Image Name="Spinner" Source="spinner.png" Width="128" Height="128" RenderTransformOrigin="0.5, 0.5">
            <Image.Triggers>
                <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                    <EventTrigger.Actions>
                        <BeginStoryboard Storyboard="{StaticResource Spin360}" />
                    </EventTrigger.Actions>
                </EventTrigger>
            </Image.Triggers>
            <Image.RenderTransform>
                <RotateTransform Angle="0" />
            </Image.RenderTransform>
        </Image>
    </Grid>
</Window>

Here is the simple Visual Studio 2010 project:

SpinAnImage.zip

Option 2 – Loop through images using a Storyboard

This option is the one you would use if you have multiple images. You can create a Storyboard that loops through all of your images. If you have a gif, you can extract each image and use them.

Here is a BlackSpinner1.png file (128×128) that I made really quickly in Paint.NET. Actually I made eight versions of this image, where the section that is gray changes in each image.

Here is how you configure your project to animate through these images.

  1. Create a default WPF Application project in visual studio.
  2. Add a folder to the project called Images.
  3. Add the images you want to loop through to the Images directory.
  4. Add a Storyboard to the resources.

Here is the Xaml.

<Window x:Class="SpinUsingMultipleImages.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Spinner using multiple images" Height="300" Width="300">
    <Grid>
        <Grid.Resources>
            <Storyboard x:Key="BlackSpinnerStoryBoard">
                <ObjectAnimationUsingKeyFrames Duration="0:0:2" Storyboard.TargetProperty="Source" RepeatBehavior="Forever">
                    <DiscreteObjectKeyFrame KeyTime="0:0:0">
                        <DiscreteObjectKeyFrame.Value>
                            <BitmapImage UriSource="Images/BlackSpinner1.png"/>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.25">
                        <DiscreteObjectKeyFrame.Value>
                            <BitmapImage UriSource="Images/BlackSpinner2.png"/>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.50">
                        <DiscreteObjectKeyFrame.Value>
                            <BitmapImage UriSource="Images/BlackSpinner3.png"/>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.75">
                        <DiscreteObjectKeyFrame.Value>
                            <BitmapImage UriSource="Images/BlackSpinner4.png"/>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                    <DiscreteObjectKeyFrame KeyTime="0:0:1">
                        <DiscreteObjectKeyFrame.Value>
                            <BitmapImage UriSource="Images/BlackSpinner5.png"/>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                    <DiscreteObjectKeyFrame KeyTime="0:0:1.25">
                        <DiscreteObjectKeyFrame.Value>
                            <BitmapImage UriSource="Images/BlackSpinner6.png"/>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                    <DiscreteObjectKeyFrame KeyTime="0:0:1.50">
                        <DiscreteObjectKeyFrame.Value>
                            <BitmapImage UriSource="Images/BlackSpinner7.png"/>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                    <DiscreteObjectKeyFrame KeyTime="0:0:1.75">
                        <DiscreteObjectKeyFrame.Value>
                            <BitmapImage UriSource="Images/BlackSpinner8.png"/>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
            </Storyboard>
        </Grid.Resources>
        <Image Name="BlackSpinner">
            <Image.Triggers>
                <EventTrigger RoutedEvent="Image.Loaded">
                    <EventTrigger.Actions>
                        <BeginStoryboard Storyboard="{StaticResource BlackSpinnerStoryBoard}" />
                    </EventTrigger.Actions>
                </EventTrigger>
            </Image.Triggers>
        </Image>
    </Grid>
</Window>

Here is a sample project attached.

SpinUsingMultipleImages.zip

4 Comments

  1. David Coleman says:

    Great solution. Only problem I had was the gif I used had 30 frames and each frame only contained the bit that differed from the previous frame. Used paint.net to layer and save each complete png. Took a while but the result is exactly what I was after and really so easy to implement. Thank you.

  2. Lawrence Mantin says:

    Nice solution!

  3. […] single best demonstration I found was at WPFSharp.  It’s all-XAML, intuitive, and complete (which is very helpful for […]

Leave a Reply to David Coleman