Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Loading Animation in WPF

DZone's Guide to

Loading Animation in WPF

Today I am going to show how to create a loading animation unit, as seen in many applications or/and websites.

· Web Dev Zone
Free Resource

Learn how to build modern digital experience apps with Crafter CMS. Download this eBook now. Brought to you in partnership with Crafter Software

WPF offers extensive functionality when it comes to graphics in client applications. Today I am going to show how to create a loading animation unit, as seen in many applications or/and websites. I am going to create it without any code-behind – only pure XAML will be used.

First of all start Visual Studio and create a new WPF application. Doesn’t matter whether it is going to be a VB.NET or C# project – I won’t be coding any functionality for this – XAML code is the same across WPF projects create in different programming languages. Take a look at the structure of the existing XAML code. It should be similar to this:

<Window x:Class="WPF_Test.Window1"    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml    Title="Window1" Height="300" Width="300">    <Grid>    </Grid></Window>


Pretty simple. Now, you need to create a circle that will serve as the loading indicator. To do this, there is the Ellipse primitive available. You can draw it directly in the designer and then adjust the properties, or you could insert this XAML snippet inside the existing grid:

<Ellipse x:Name="ellipse" Margin="55,49,54,38" StrokeThickness="20" RenderTransformOrigin="0.5,0.5"></Ellipse>


As you see, first of all I am setting the name. It is completely up to you what this is going to be. The margins are set according to the size of the window (or the container where the ellipse is located). In this specific case, I set the ellipse to almost cover the entire window. The margins are set for a perfect circle. The StrokeThickness property can be adjusted as the developer wants, however, I would recommend keeping it several units thicker than 1, because it will be the key element that will facilitate the progress animation. Since the gradient will be transformed, there is the RenderTransformOrigin property that sets the transformation point for the current element. The values range between 0 and 1, therefore a value of 0.5 will set the transformation point to the center of the object.

Now, let’s go to the transformation code. Add this snippet inside the Ellipse element:

<Ellipse.RenderTransform>    <TransformGroup>        <ScaleTransform/>        <SkewTransform/>        <RotateTransform/>    </TransformGroup></Ellipse.RenderTransform>

These are the required transformations that will be performed on the ellipse, although it will be rotated only. Now, let’s set the gradient for the stroke. Here is the XAML snippet that should be placed inside the root Ellipse element:

<Ellipse.Stroke>    <LinearGradientBrush EndPoint="0.445,0.997" StartPoint="0.555,0.003">        <GradientStop Color="White" Offset="0"/>        <GradientStop Color="#FF0052FF" Offset="1"/>    </LinearGradientBrush></Ellipse.Stroke>

The gradient start and end points can be adjusted as the developer wants. In this specific case, I set them so it is equally distributing the color across the circle, one side being light blue and the other one white (that can be seen from the color declarations).

To actually perform an animation, a storyboard is needed, so I am going to add a new container element inside the root Window element:

<Window.Resources></Window.Resources>

This will be the place holder for the additional resources I am going to introduce. In fact, in this tutorial I will only be adding a storyboard inside:

<Storyboard x:Key="Storyboard1" RepeatBehavior="Forever"></Storyboard>

Once again, the name is completely random. You can change it if you want to, just make sure you introduce proper references later on in the code. The RepeatBehavior property is set to Forever, this meaning that the animation will be continuous.  You can remove this property from the declaration, but in this case the animation will only happen once. Now, the animation itself is placed inside the storyboard:

<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">    <SplineDoubleKeyFrame KeyTime="00:00:02" Value="360"/></DoubleAnimationUsingKeyFrames>

The BeginTime property shows when the animation will begin. If you want to introduce a delay to the animation, you can alter this setting accordingly. Storyboard.TargetName is the target of the animation – the ellipse in this case. Storyboard.TargetProperty is the property that will be modified. The DoubleAnimationUsingKeyFrames itself shows that a property (with values of type Double) will be animated.

The SplineDoubleKeyFrame shows the end time for the animation and the end value of the property that will be modified.

Almost there, but the animation needs to be triggered. For this purpose, I am adding the Window.Triggers element to the root Window element:

<Window.Triggers>  <EventTrigger RoutedEvent="FrameworkElement.Loaded">    <BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>  </EventTrigger></Window.Triggers>

This will cause the animation to load when the window is loaded and will start it from the storyboard created above. Now, build and run the application. The end result should look similar to this:

The complete XAML code for the window:

<Window x:Class="WPF_Test.Window1"    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml    Title="Window1" Height="300" Width="300">    <Window.Resources>        <Storyboard x:Key="Storyboard1" RepeatBehavior="Forever">            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">                <SplineDoubleKeyFrame KeyTime="00:00:02" Value="360"/>            </DoubleAnimationUsingKeyFrames>        </Storyboard>    </Window.Resources>    <Window.Triggers>        <EventTrigger RoutedEvent="FrameworkElement.Loaded">            <BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>        </EventTrigger>    </Window.Triggers>    <Grid>        <Ellipse x:Name="ellipse" Margin="55,49,54,38" StrokeThickness="20" RenderTransformOrigin="0.5,0.5">            <Ellipse.RenderTransform>                <TransformGroup>                    <ScaleTransform/>                    <SkewTransform/>                    <RotateTransform/>                </TransformGroup>            </Ellipse.RenderTransform>            <Ellipse.Stroke>                <LinearGradientBrush EndPoint="0.445,0.997" StartPoint="0.555,0.003">                    <GradientStop Color="White" Offset="0"/>                    <GradientStop Color="#FF0052FF" Offset="1"/>                </LinearGradientBrush>            </Ellipse.Stroke>        </Ellipse>            </Grid></Window>

Crafter is a modern CMS platform for building modern websites and content-rich digital experiences. Download this eBook now. Brought to you in partnership with Crafter Software.

Topics:
dotnet ,loading ,animation ,wpf ,xaml ,c-sharp

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}