Click here to Skip to main content
Click here to Skip to main content

WPF: Round Progress Bar

By , 12 Jul 2009
 

Introduction

The standard WPF progress bar is very boring, and doesn't allows lot of customizations. I created a round progress bar like the ones that I always see in the web and in Flash applications.

Here is the simple idea of how to implement such a control. I used two Canvases, a TextBox and 12 Rectangles to create the progress bar.

Here is the XAML code of the UserControl:

<UserControl x:Class="RounderProgressBar.RounderProgressBarControl"  
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml 
    Height="400" Width="400">

    <UserControl.Resources>  
        <Style x:Key="canvasStyle" TargetType="{x:Type Canvas}"> 
            <Setter Property="Background" Value="Transparent"/> 
        </Style>  
        <Style x:Key ="rectangle" 
                     TargetType="{x:Type Rectangle}"> 
            <Setter Property="Width" Value="35"/> 
            <Setter Property="Height" Value="100"/> 
            <Setter Property="Fill" Value="LightBlue"/> 
            <Setter Property="Canvas.Left" Value="190"/> 
            <Setter Property="Canvas.Top" Value="0"/> 
            <Setter Property="RadiusX" Value="10"/> 
            <Setter Property="RadiusY" Value="10"/> 
        </Style> 
        <Style x:Key="percents" TargetType="{x:Type TextBox}">
            <Setter Property="FontSize" Value="20" />
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="IsReadOnly" Value="true"/>
        </Style>      
    </UserControl.Resources> 

    <Canvas RenderTransformOrigin="0.5,0.5" 
             Style="{StaticResource canvasStyle}"> 
        <TextBox Name="tbPercents" 
          Style="{StaticResource percents}"  
          Canvas.Left="172" Canvas.Top="189" 
          TextChanged="tblPercents_TextChanged"> 
            100% 
        </TextBox>         
        <Canvas Name="rotationCanvas" 
               RenderTransformOrigin="0.5,0.5" 
               Style="{StaticResource canvasStyle}"> 
            <Rectangle  Style="{StaticResource rectangle}"> 
            </Rectangle> 
            <Rectangle Opacity="0.92" 
                    Style="{StaticResource rectangle}"> 
                <Rectangle.RenderTransform> 
                    <RotateTransform Angle="30" 
                            CenterX="10" CenterY="200"/> 
                </Rectangle.RenderTransform> 
            </Rectangle> 
            <Rectangle Opacity="0.84" 
                    Style="{StaticResource rectangle}"> 
                <Rectangle.RenderTransform> 
                    <RotateTransform Angle="60" 
                           CenterX="10" CenterY="200"/> 
                </Rectangle.RenderTransform> 
            </Rectangle> 
            <Rectangle Opacity="0.76" 
                     Style="{StaticResource rectangle}" > 
                <Rectangle.RenderTransform> 
                    <RotateTransform Angle="90" 
                          CenterX="10" CenterY="200"/> 
                </Rectangle.RenderTransform> 
            </Rectangle> 
            <Rectangle Opacity="0.66" 
                   Style="{StaticResource rectangle}"> 
                <Rectangle.RenderTransform> 
                    <RotateTransform Angle="120" 
                         CenterX="10" CenterY="200"/> 
                </Rectangle.RenderTransform> 
            </Rectangle> 
            <Rectangle Opacity="0.58" 
                      Style="{StaticResource rectangle}" > 
                <Rectangle.RenderTransform> 
                    <RotateTransform Angle="150" 
                           CenterX="10" CenterY="200"/> 
                </Rectangle.RenderTransform> 
            </Rectangle> 
            <Rectangle Opacity="0.5" 
                      Style="{StaticResource rectangle}" > 
                <Rectangle.RenderTransform> 
                    <RotateTransform Angle="180" 
                          CenterX="10" CenterY="200"/> 
                </Rectangle.RenderTransform> 
            </Rectangle> 
            <Rectangle Opacity="0.42" 
                    Style="{StaticResource rectangle}" > 
                <Rectangle.RenderTransform> 
                    <RotateTransform Angle="210" 
                      CenterX="10" CenterY="200"/> 
                </Rectangle.RenderTransform> 
            </Rectangle> 
            <Rectangle Opacity="0.34" 
                      Style="{StaticResource rectangle}" > 
                <Rectangle.RenderTransform> 
                    <RotateTransform Angle="240" 
                      CenterX="10" CenterY="200"/> 
                </Rectangle.RenderTransform> 
            </Rectangle> 
            <Rectangle Opacity="0.26" 
                  Style="{StaticResource rectangle}" > 
                <Rectangle.RenderTransform> 
                    <RotateTransform Angle="270" 
                      CenterX="10" CenterY="200"/> 
                </Rectangle.RenderTransform> 
            </Rectangle> 
            <Rectangle Opacity="0.16" 
                 Style="{StaticResource rectangle}" > 
                <Rectangle.RenderTransform> 
                    <RotateTransform Angle="300" 
                      CenterX="10" CenterY="200"/> 
                </Rectangle.RenderTransform> 
            </Rectangle> 
            <Rectangle Opacity="0.08" 
                   Style="{StaticResource rectangle}" > 
                <Rectangle.RenderTransform> 
                    <RotateTransform Angle="330" 
                       CenterX="10" CenterY="200"/> 
                </Rectangle.RenderTransform> 
            </Rectangle> 
            <Canvas.RenderTransform> 
                <RotateTransform x:Name="SpinnerRotate"  
                   Angle="0" CenterX="200" 
                   CenterY="200" /> 
            </Canvas.RenderTransform> 
        </Canvas> 
    </Canvas> 
</UserControl>

To add some animation to the progress bar, I use a System.Timer and rotate the second Canvas on 30 angles every 100 milliseconds.

Here is the code in С#:

using System.Timers; 
using System.Windows; 
using System.Windows.Controls;

namespace RounderProgressBar 
{ 
    /// <summary> 
    /// Interaction logic for RounderProgressBar.xaml 
    /// </summary> 
    public partial class RounderProgressBarControl : UserControl 
    { 
        private const string PERCENTS_TEXT = "{0}%"; 
        private delegate void VoidDelegete(); 
        private Timer timer; 
        private bool loaded; 
        private int progress; 

        public RounderProgressBarControl() 
        { 
            InitializeComponent(); 
            Loaded += OnLoaded; 
        }

        void OnLoaded(object sender, RoutedEventArgs e) 
        { 
            timer = new Timer(100); 
            timer.Elapsed += OnTimerElapsed; 
            timer.Start(); 
            loaded = true; 
        }

        void OnTimerElapsed(object sender, ElapsedEventArgs e) 
        { 
            rotationCanvas.Dispatcher.Invoke 
            ( 
                new VoidDelegete( 
                    delegate 
                        { 
                            SpinnerRotate.Angle += 30; 
                            if (SpinnerRotate.Angle == 360) 
                            { 
                                SpinnerRotate.Angle = 0; 
                            } 
                        } 
                    ), 
                null 
            );  
        }

        private void tblPercents_TextChanged(object sender, 
                     TextChangedEventArgs e) 
        { 
            if (loaded) 
            { 
                Canvas.SetLeft(tbPercents, 
                  (rotationCanvas.ActualHeight - tbPercents.ActualWidth) / 2); 
                Canvas.SetTop(tbPercents, 
                  (rotationCanvas.ActualHeight - tbPercents.ActualHeight) / 2);    
            } 
        } 

        private void UpdateProgress() 
        { 
            tbPercents.Text = string.Format(PERCENTS_TEXT, progress); 
        } 

        public int Progress 
        { 
            get { return progress; } 
            set 
            { 
                progress = value; 
                UpdateProgress(); 
            } 
        } 
    } 
}

You can easily change the percentage info on the progress bar using the Progress property.

public int Progress 
{  
    get { return progress; } 

    set 
    { 
        progress = value; 
        UpdateProgress(); 
    }  
}

License

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

About the Author

NeoPunk
Belarus Belarus
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionIts not working with asynchronous call [modified]memberMember 34620802 Mar '12 - 20:21 
Its not working with asynchronous call. Like I start the that bar and then start my work and then stop the bar. But it not working.
 
//Bar start
//My work
//Bar Stop
 
But its not behave like that
 

You can download the sample from here
 
Progress Bar

modified 3 Mar '12 - 2:59.

QuestionProgress not work!memberAli_MH22 May '11 - 20:36 
Hi
First Thanks for article. Wink | ;)
 
Now i want to use this progress bar to calculate some incremntal process for example incement integer variable in for loop, i set Progress value in loop, but progress view does not show percent process, why? Confused | :confused:
 
Other issue is visibility of control when i put it into viewbox to change it size, in that way progress bar does not show anymore. :(
Generalweird progress bar shows up as top CPU drain on ANTS Profilermemberdevvvy6 Mar '11 - 8:43 
weird progress bar shows up as top CPU drain on ANTS Profiler, you can't really downgrade 100 ms intervals to say 1000 ms, which would be too slow.
 

void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
rotationCanvas.Dispatcher.Invoke
(
new VoidDelegete(
delegate
{
SpinnerRotate.Angle += 30;
if (SpinnerRotate.Angle == 360)
{
SpinnerRotate.Angle = 0;
}
}
),
null
);
}

dev

GeneralRe: weird progress bar shows up as top CPU drain on ANTS ProfilermemberNeoPunk6 Mar '11 - 11:24 
Possibly it is profile's problem. I exactly know if profile attached application performance is too low, try it without profile. As i can see on my workstation (I have Core i5 on it), progress bar doesn't use CPU at all.
GeneralMy vote of 5memberkkirusha21 Nov '10 - 11:36 
Thanks for code.
GeneralA good start...memberJosh Fischer11 Aug '09 - 7:53 
> The standard WPF progress bar is very boring, and doesn't allows lot of customizations.
 
I have to disagree here. I think your solution is a good start, but if you look HERE you will see there is a lot more you can do in XAML without relying on the code-behind.
It took me a while to switch my thinking to the "xaml" way, but it's hard to argue with Charles Petzold and his results. Shucks | :->
 
Josh Fischer

GeneralRe: A good start...memberKirill Kovalev14 Aug '09 - 19:22 
Microsoft article shows how you can create custom progressbar using "ControlTemplate" but there are no way to create circular progressbar.
QuestionResize?memberDaProgramma25 Jul '09 - 2:40 
Nice approach.
But the size is always the same. How can I make the display fit a given size?
 
Greetz - daProgramma
AnswerRe: Resize?memberKirill Kovalev25 Jul '09 - 23:17 
You can put control into ViewBox.
 
Something like this:
<Viewbox>
<RounderProgressBar:RounderProgressBarControl/>
</Viewbox>
QuestionArchive Sizemembersotona12 Jul '09 - 4:16 
Откуда такой дикий размер? Is there some empty BMP file in archive?
AnswerRe: Archive SizememberKirill Kovalev12 Jul '09 - 6:54 
I forgot to delete "ReSharper" temporary files.

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 12 Jul 2009
Article Copyright 2009 by NeoPunk
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid