Click here to Skip to main content
11,579,898 members (72,099 online)
Click here to Skip to main content

Tagged as

Better WPF Circular Progress Bar

, 4 Jan 2010 CPOL 73.3K 1 40
Rate this:
Please Sign up or sign in to vote.
A while back I posted a blog post about a simple Circular Progress Bar that I did for WPF. The original post is right here : http://sachabarber.net/?p=429It turns out that was not the best thing to do, as the old approach used a never ending animation, that was even running when the controls Visibil

A while back I posted a blog post about a simple Circular Progress Bar that I did for WPF. The original post is right here : http://sachabarber.net/?p=429

It turns out that was not the best thing to do, as the old approach used a never ending animation, that was even running when the controls Visibility changed. I did notice this pretty quickly, when we profiled our app, and noticed this hot spot exactly where the progress bar was. So what we did to fix that is just remove the control when it should stop showing progress. Anyway that was the old way.

I am pleased to announce that I have a new improved Circular Progress Bar that no longer uses a never ending animation, in fact it is a lot simpler and just uses a DispatcherTimer and some elementary trigonometry, and it actually looks more like the style of progress bar we are all used to seeing on the web. Without further ado here is the code:

The xaml for the CircularProgressBar.xaml

<UserControl x:Class="ThreadingComponent.CircularProgressBar"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="Auto" Width="Auto" Background="Transparent"
             IsVisibleChanged="HandleVisibleChanged">
    <Grid x:Name="LayoutRoot" Background="Transparent"
          ToolTip="Searching...."
          HorizontalAlignment="Center"
          VerticalAlignment="Center">
        <Canvas RenderTransformOrigin="0.5,0.5"
                HorizontalAlignment="Center"
             VerticalAlignment="Center" Width="120"
             Height="120" Loaded="HandleLoaded"
                Unloaded="HandleUnloaded"  >
            <Ellipse x:Name="C0" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="1.0"/>
            <Ellipse x:Name="C1" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.9"/>
            <Ellipse x:Name="C2" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.8"/>
            <Ellipse x:Name="C3" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.7"/>
            <Ellipse x:Name="C4" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.6"/>
            <Ellipse x:Name="C5" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.5"/>
            <Ellipse x:Name="C6" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.4"/>
            <Ellipse x:Name="C7" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.3"/>
            <Ellipse x:Name="C8" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.2"/>
            <Canvas.RenderTransform>
                <RotateTransform x:Name="SpinnerRotate"
                     Angle="0" />
            </Canvas.RenderTransform>
        </Canvas>
    </Grid>
</UserControl>

And here is the CircularProgressBar.xaml.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Windows.Input;
using System.Windows.Shapes;

namespace ThreadingComponent
{
    /// <span class="code-SummaryComment"><summary>
</span>    /// A circular type progress bar, that is simliar to popular web based
    /// progress bars
    /// <span class="code-SummaryComment"></summary>
</span>    public partial class CircularProgressBar
    {
        #region Data
        private readonly DispatcherTimer animationTimer;
        #endregion

        #region Constructor
        public CircularProgressBar()
        {
            InitializeComponent();

            animationTimer = new DispatcherTimer(
                DispatcherPriority.ContextIdle, Dispatcher);
            animationTimer.Interval = new TimeSpan(0, 0, 0, 0, 75);
        }
        #endregion

        #region Private Methods
        private void Start()
        {
            Mouse.OverrideCursor = Cursors.Wait;
            animationTimer.Tick += HandleAnimationTick;
            animationTimer.Start();
        }

        private void Stop()
        {
            animationTimer.Stop();
            Mouse.OverrideCursor = Cursors.Arrow;
            animationTimer.Tick -= HandleAnimationTick;
        }

        private void HandleAnimationTick(object sender, EventArgs e)
        {
            SpinnerRotate.Angle = (SpinnerRotate.Angle + 36) % 360;
        }

        private void HandleLoaded(object sender, RoutedEventArgs e)
        {
            const double offset = Math.PI;
            const double step = Math.PI * 2 / 10.0;

            SetPosition(C0, offset, 0.0, step);
            SetPosition(C1, offset, 1.0, step);
            SetPosition(C2, offset, 2.0, step);
            SetPosition(C3, offset, 3.0, step);
            SetPosition(C4, offset, 4.0, step);
            SetPosition(C5, offset, 5.0, step);
            SetPosition(C6, offset, 6.0, step);
            SetPosition(C7, offset, 7.0, step);
            SetPosition(C8, offset, 8.0, step);
        }

        private void SetPosition(Ellipse ellipse, double offset,
            double posOffSet, double step)
        {
            ellipse.SetValue(Canvas.LeftProperty, 50.0
                + Math.Sin(offset + posOffSet * step) * 50.0);

            ellipse.SetValue(Canvas.TopProperty, 50
                + Math.Cos(offset + posOffSet * step) * 50.0);
        }

        private void HandleUnloaded(object sender, RoutedEventArgs e)
        {
            Stop();
        }

        private void HandleVisibleChanged(object sender,
            DependencyPropertyChangedEventArgs e)
        {
            bool isVisible = (bool)e.NewValue;

            if (isVisible)
                Start();
            else
                Stop();
        }
        #endregion
    }
}

And to use it you can simply make it any size you like by putting it into a ViewBox like so:

<UserControl x:Class="ThreadingComponent.BusyUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ThreadingComponent"
    Height="Auto" Width="Auto"
    HorizontalAlignment="Stretch"
    VerticalAlignment="Stretch">

        <Viewbox Width="200" Height="200"
                HorizontalAlignment="Center"
                VerticalAlignment="Center">
            <local:CircularProgressBar />
        </Viewbox>

    </Grid>

</UserControl>

And here is what it looks like when its running

All the code is here is a cut and pastable format, so no ZIP file this time, just cut and paste this code, if you don’t know how to do that, step away from the XAML.

License

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

Share

About the Author

Sacha Barber
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

You may also be interested in...

Comments and Discussions

 
GeneralThanks Pin
K.Vishwa24-Jun-15 6:06
memberK.Vishwa24-Jun-15 6:06 
BugError Pin
Member 1152561613-Jun-15 23:28
memberMember 1152561613-Jun-15 23:28 
QuestionError Pin
Member 1152561613-Jun-15 22:56
memberMember 1152561613-Jun-15 22:56 
QuestionHow to increase the size of the circle? Pin
Anishaaaaa5-Feb-15 3:00
memberAnishaaaaa5-Feb-15 3:00 
QuestionThank!!!!! Pin
JustMe4TheCodeProject4-Oct-14 22:21
memberJustMe4TheCodeProject4-Oct-14 22:21 
SuggestionRe-done to make it a WPF Custom control Pin
Member 79875048-Apr-14 10:39
memberMember 79875048-Apr-14 10:39 
GeneralRe: Re-done to make it a WPF Custom control Pin
Sacha Barber8-Apr-14 12:02
mvpSacha Barber8-Apr-14 12:02 
SuggestionViewbox optimization Pin
pr0gg3r12-Apr-13 2:42
memberpr0gg3r12-Apr-13 2:42 
QuestionCircular Progress bar not updating unless I move the window it is in Pin
coolestnerd30-Sep-11 2:29
membercoolestnerd30-Sep-11 2:29 
AnswerRe: Circular Progress bar not updating unless I move the window it is in Pin
coolestnerd30-Sep-11 3:21
membercoolestnerd30-Sep-11 3:21 
GeneralRe: Circular Progress bar not updating unless I move the window it is in Pin
Sacha Barber1-Oct-11 10:36
mvpSacha Barber1-Oct-11 10:36 
GeneralMy vote of 4 Pin
isaks10-Jul-11 0:47
memberisaks10-Jul-11 0:47 
GeneralMy vote of 5 Pin
Tawani Anyangwe12-Mar-11 8:01
memberTawani Anyangwe12-Mar-11 8:01 
GeneralMy vote of 5 Pin
radupoe23-Oct-10 9:15
memberradupoe23-Oct-10 9:15 
GeneralMouse.OverrideCursor Pin
EinarG8-Jun-10 2:23
memberEinarG8-Jun-10 2:23 
GeneralRe: Mouse.OverrideCursor Pin
Sacha Barber8-Jun-10 2:23
mvpSacha Barber8-Jun-10 2:23 
GeneralPlace 2 controls CircularProgressBar Pin
Member 36659934-May-10 7:55
memberMember 36659934-May-10 7:55 
GeneralRe: Place 2 controls CircularProgressBar Pin
Sacha Barber4-May-10 8:07
mvpSacha Barber4-May-10 8:07 
GeneralRe: Place 2 controls CircularProgressBar Pin
Member 36659934-May-10 10:01
memberMember 36659934-May-10 10:01 
GeneralAn attempt to improve further based on your code Pin
Raja.Lakshman3-Apr-10 14:29
memberRaja.Lakshman3-Apr-10 14:29 
GeneralThanks for your help Pin
Jeremy Hutchinson11-Feb-10 2:52
memberJeremy Hutchinson11-Feb-10 2:52 
GeneralThanks Pin
Member 112495512-Jan-10 7:09
memberMember 112495512-Jan-10 7:09 
GeneralRe: Thanks Pin
Sacha Barber12-Jan-10 9:23
mvpSacha Barber12-Jan-10 9:23 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150603.1 | Last Updated 4 Jan 2010
Article Copyright 2010 by Sacha Barber
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid