How to Create a Circular Loader using XAML?


Circular Loader

Sometime we need to show a circular loader in WPF and/or Silverlight. We may need it in Windows Phone 7 too. In simple statement, we need to show a circular loader in various XAML applications like Silverlight, WP7 and WPF.

 

In this article, we will learn how to create a Circular Loader as shown in the screenshot. I will not use a single line of C# code to create this loader. Everything will be in the XAML file itself to keep the code behind file clean. Read to know more about it step-by-step and after reading this article, you will be able to create and use a circular loader like this. Source code is also available for download at the end of the page. Feel free to use it.

 

Setup the Project

First, we need to create a Silverlight project. Here we will create a Silverlight 4 Application project. Once you are done with the project creation, right click on the Silverlight project and add a new UserControl. We will use this as the circular loader. As shown in the below screenshot, select the "Silverlight User Control" template and provide a name "CircularLoader.xaml" and hit "Add" to continue.

 

Loader Demo - Create a new UserControl called CircularLoader.xaml

 

This will create a new UserControl in your solution project. Once done with this step, it's time to create the UI of the loader control. Then we will integrate it to the MainPage.xaml and see how it looks.

 

Create the UI of the Circular Loader

Now time to create the XAML of the loader. Remember that, we will not have a single line of C# code. Everything will be done in the XAML. If you are expert with Expression Blend, you can create it very easily. But here we will use direct XAML code to demonstrate the same. It will be helpful for you to understand properly.

 

Let's open the usercontrol xaml file and replace the original Grid control with a ViewBox control. You may ask one question here: Why should I use a ViewBox? Yes my friend, a very good question. ViewBox will allow you to resize the content of the panel with respect to parent container. This means if you explicitly increase or decrease the size of the user control, the inner content will proportionally resize as per the container size.

 

Now we will add a Canvas inside the ViewBox, so that, we can properly place the circles inside it in proper (x, y) coordinates.

 

After this step, we need to add some Ellipse control inside the Canvas panel to create a Circle. We will fill the color of the Ellipse with the Foreground color of the UserControl. We will use proper binding to do this, as shown below:

 
<Ellipse Fill="{Binding Foreground, ElementName=userControl}" 
         Height="71" Canvas.Left="121" Canvas.Top="21" Width="69" Opacity="0.3"/>

 

In the above code snippet, you can see that, we added Canvas.Left and Canvas.Top to position the circle. Similarly, we will add some more circles using the Ellipse control and position them properly to create a circular path.

 

Setting the Opacity of the Circles

We need to set the opacity of the circles to create the similar look as we wanted to develop. Opacity will ensure that, we will use the same color but different transparency to create the UI.

 

Find the below XAML code for reference:

 

Loader Demo - Designing the Loader Circles with Proper Opacity Value

 

Have a look into the above XAML code. You will see there how we placed the circles in proper coordinate positions. Also check the opacity that we set for each individual circles.

 

Adding RenderTransform to the Canvas

Once you are done with the UI, you need to set the RenderTransform to the canvas. This step is require to keep the circle rotating in the orbit. We will add a composite transform to the canvas as shown below:

 

Loader Demo - Adding RenderTransform to the Canvas

 

Our animation that we will create in the next step will use the same transform of the canvas to rotate the circles in the circular orbit.

 

Find the complete code of the UI here, in case you need proper visibility on the code that we created just now:

 
<Viewbox x:Name="LayoutRoot" HorizontalAlignment="Left" VerticalAlignment="Top">
    <Canvas x:Name="canvas" Height="323" Width="308" RenderTransformOrigin="0.5,0.5">
        <Canvas.RenderTransform>
            <CompositeTransform/>
        </Canvas.RenderTransform>
        <Ellipse Fill="{Binding Foreground, ElementName=userControl}" 
                 Height="71" Canvas.Left="121" Canvas.Top="21" Width="69" Opacity="0.3"/>
        <Ellipse Fill="{Binding Foreground, ElementName=userControl}" 
                 Height="71" Width="69" Canvas.Left="194" Canvas.Top="52" Opacity="0.4"/>
        <Ellipse Fill="{Binding Foreground, ElementName=userControl}" 
                 Width="69" Height="71" Canvas.Left="221" Canvas.Top="123" Opacity="0.5"/>
        <Ellipse Fill="{Binding Foreground, ElementName=userControl}" 
                 Width="69" Height="71" Canvas.Left="190" Canvas.Top="198" Opacity="0.6"/>
        <Ellipse Fill="{Binding Foreground, ElementName=userControl}" 
                 Height="71" Canvas.Left="121" Canvas.Top="226" Width="69" Opacity="0.7"/>
        <Ellipse Fill="{Binding Foreground, ElementName=userControl}" 
                 Width="69" Height="71" Canvas.Left="48" Canvas.Top="194" Opacity="0.8"/>
        <Ellipse Fill="{Binding Foreground, ElementName=userControl}" 
                 Height="71" Width="69" Canvas.Left="17" Canvas.Top="123" Opacity="0.9"/>
        <Ellipse Fill="{Binding Foreground, ElementName=userControl}" 
                 Height="71" Width="69" Canvas.Left="48" Canvas.Top="52" Opacity="1.0"/>
    </Canvas>
</Viewbox>

 

 

Create the Storyboard

Now what we need in this step? We need to create a smooth animation which we can achieve using the StoryBoard. We will create a Storyboard now to rotate the circles in the orbit. You can use the Expression Blend to create the animation easily. As this is a simpler code, I am just sharing the code for you here:

 
<UserControl.Resources>
    <Storyboard x:Name="LoaderAnimation">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)" 
                                       Storyboard.TargetName="canvas" 
                                       RepeatBehavior="Forever">
            <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
            <EasingDoubleKeyFrame KeyTime="0:0:3" Value="360"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</UserControl.Resources>

 

The storyboard will rotate the canvas to 360 degree to give a circular motion to the circles. Also we will set the RepeatBehavior to indefinite by setting the value "Forever". Here the storyboard will be available as a Resource to the UserControl. Hence we can easily access it whenever require.

 

Once the storyboard has been created, we need to run it on load. The simplest approach here will be calling the Begin() method of the storyboard from code behind class. As I told, we will not write a single line in the code behind, we need to do something from the XAML which will cause the storyboard to run.

 

We can achieve this functionality be using the Microsoft.Expression.Interactions and System.Windows.Interactivity dll assemblies. They provides interfaces to call a storyboard on some event. To do this, we need to add the assembly references of those dlls. Add them from the "Add Reference" dialog as shown below:

 

Loader Demo - Adding External Libraries (Microsoft.Expression.Interactions and System.Windows.Interactivity)

 

Once you added the assembly references, we will add the following xmlns namespaces in the xaml file. Those two namespace will help us to call the storyboard easily from the xaml without writing any code behind file.

 

Loader Demo - Adding xmlns Namespaces in the XAML

 

Just after the resource declaration, add the below code:

 
<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <ei:ControlStoryboardAction Storyboard="{StaticResource LoaderAnimation}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

 

This will run the storyboard from the loaded event. That means, once the usercontrol has been loaded in the UI, it will call the Storyboard to start executing the animation.

 

See it in Action

Upto this, our code is ready. Now, add the said CurcularLoader.xaml UserControl in the MainPage.xaml file. We will place it inside the LayoutRoot. Make sure to set a Foreground color for the circles. Build the solution and check if there are any error. If so, fix them and run the project. You will see the following UI inside the browser window:

 

Loader Demo - Showing Demo of the Loader Control

 

If you resize the browser, it will change the size of the circular loader in proportion to the parent panel. Now we will do a little change here. While adding the user control in the main page, we will specify it's height and width. For our example, we will use 50 x 50 as the dimension of the loader control.

 

Find the complete source code of the MainPage.xaml where we added the loader control:

 
<UserControl x:Class="LoaderDemo.MainPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:LoaderDemo="clr-namespace:LoaderDemo">
    <Grid>
        <LoaderDemo:CircularLoader Foreground="Black" 
                                   HorizontalAlignment="Center" 
                                   VerticalAlignment="Center"
                                   Height="50" Width="50"/>
    </Grid>
</UserControl>

 

Now once you run the application again, you will see the following UI where the loader control has a fixed size:

 

Loader Demo - Showing Demo of the Loader Control after Resize

 

In this case, if you resize the browser, it will not change it's size because now it has a proper dimension. Hope, you enjoyed reading the article. This helped you to understand the same in depth. Now you will be able to modify the same code and implement additional behavior. You can also expose some APIs on need basis.

 

Download Source Code

Do you need the source code of the project for your reference? Yes, you can download it from here:


If you have come this far, it means that you liked what you are reading. Why not reach little more and connect with me directly on Twitter, Facebook, Google+ and LinkedIn. I would love to hear your thoughts and opinions on my articles directly. Also, don't forget to share your views and/or feedback in the comment section below.

5 comments

  1. Hi, After creating this , I can't able to add this any bussiness application. Because all time it is rotating , I need to show this when the data is loading from database and after loading is finished , this should be vanish. Yes like Proressbar/busy indicator.

    I'm using WCF service method to call the data from database.How can I develop this .

    I need to make a custom control of this so that it will be very easy to anytime drop this in UI from toolbox and show this as a busy indicator .

    ReplyDelete
  2. Hi Debal,

    You need to expose some APIs to start and stop the animation. You can also expose APIs to show or hide the progress indicator. This tutorial demonstrates the process to create the loader animation. Rest you have to develop as per your business need. You can also try with putting the control in a busy indicator.

    Let me know, if you need further help.

    ReplyDelete
  3. Hello, I'm trying to get your picasa feed to work. Do I need to load this seperately, or is this included in the Picasa source code? When I run the Picasa app from your source code, it sits there with an unmoving clock, it won't load or do anything. Any suggestions? Thanks!

    ReplyDelete
  4. Hi Kyle, yes, the loader is already available in the Picasa project. Let me know, what exactly the issue is by running the app in debug mode.

    ReplyDelete
  5. Great example.

    I based mine on this one but instead of calculating coordinates for each ellipse, I did a rotation transform on each one from the first one with a center point in the center of the canvas.

    I just put a grid around with visibility binded so I can show or hide.



    [Style TargetType="{x:Type Ellipse}"]
    [Setter Property="Width" Value="30"/]
    [Setter Property="Height" Value="30"/]
    [Setter Property="Canvas.Left" Value="135"/]
    [Setter Property="Canvas.Top" Value="15"/]
    [Setter Property="RenderTransformOrigin" Value="0.5,4.5"/]
    [Setter Property="Fill" Value="{Binding Foreground, ElementName=Loader}"/]
    [/Style]

    [Ellipse Opacity="0.0625"/]
    [Ellipse Opacity="0.125"]
    [Ellipse.RenderTransform]
    [TransformGroup]
    [RotateTransform Angle="22.5"/]
    [/TransformGroup]
    [/Ellipse.RenderTransform]
    [/Ellipse]
    [Ellipse Opacity="0.1875"]
    [Ellipse.RenderTransform]
    [TransformGroup]
    [RotateTransform Angle="45"/]
    [/TransformGroup]
    [/Ellipse.RenderTransform]
    [/Ellipse]...

    ReplyDelete

 
© 2008-2016 Kunal-Chowdhury.com - Microsoft Technology Blog for developers and consumers | Designed by Kunal Chowdhury
Back to top