ProgressRing in Windows Phone 8

All Windows 8 app developers know “ProgressRing” which represents a control that indicates that an operation is ongoing. The typical visual appearance is a ring-shaped “spinner” that cycles an animation as progress continues.

We call it in Windows 8 from the below XAML code

<StackPanel Orientation="Horizontal">
    <ToggleSwitch Header="Toggle Switch Example" OffContent="Do work" 
             OnContent="Working" Toggled="ToggleSwitch_Toggled"/>  
    <ProgressRing x:Name="progress1"/>
</StackPanel>

This Progress Ring control is very neat then Progress Bar control. But the problem is in Windows Phone 8 is this Progress Ring is not available there. So here I am going to show you how to create this Progress Ring in Windows Phone 8 with C#.

ProgressRing

Step 1

Create a new class with ProgressRing.cs and replace its codes with the below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace IshamControls.WindowsPhone.Controls
{
    public class ProgressRing : Control
    {
        bool hasAppliedTemplate = false;

        public ProgressRing()
        {
            this.DefaultStyleKey = typeof(ProgressRing);
            TemplateSettings = new TemplateSettingValues(60);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            hasAppliedTemplate = true;
            UpdateState(this.IsActive);
        }

        void UpdateState(bool isActive)
        {
            if (hasAppliedTemplate)
            {
                string state = isActive ? "Active" : "Inactive";
                System.Windows.VisualStateManager.GoToState(this, state, true);
            }
        }

        protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize)
        {
            var width = 100D;
            if (!System.ComponentModel.DesignerProperties.IsInDesignTool)
                width = this.Width != double.NaN ? this.Width : availableSize.Width;
            TemplateSettings = new TemplateSettingValues(width);
            return base.MeasureOverride(availableSize);
        }

        public bool IsActive
        {
            get { return (bool)GetValue(IsActiveProperty); }
            set { SetValue(IsActiveProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsActive.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsActiveProperty =
            DependencyProperty.Register("IsActive", typeof(bool), typeof(ProgressRing), new PropertyMetadata(false, new PropertyChangedCallback(IsActiveChanged)));

        private static void IsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
        {
            var pr = (ProgressRing)d;
            var isActive = (bool)args.NewValue;
            pr.UpdateState(isActive);
        }

        public TemplateSettingValues TemplateSettings
        {
            get { return (TemplateSettingValues)GetValue(TemplateSettingsProperty); }
            set { SetValue(TemplateSettingsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TemplateSettings.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TemplateSettingsProperty =
            DependencyProperty.Register("TemplateSettings", typeof(TemplateSettingValues), typeof(ProgressRing), new PropertyMetadata(new TemplateSettingValues(100)));

        public class TemplateSettingValues : System.Windows.DependencyObject
        {
            public TemplateSettingValues(double width)
            {
                MaxSideLength = 400;
                EllipseDiameter = width / 10;
                EllipseOffset = new System.Windows.Thickness(EllipseDiameter);
            }

            public double MaxSideLength
            {
                get { return (double)GetValue(MaxSideLengthProperty); }
                set { SetValue(MaxSideLengthProperty, value); }
            }

            // Using a DependencyProperty as the backing store for MaxSideLength.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty MaxSideLengthProperty =
                DependencyProperty.Register("MaxSideLength", typeof(double), typeof(TemplateSettingValues), new PropertyMetadata(0D));

            public double EllipseDiameter
            {
                get { return (double)GetValue(EllipseDiameterProperty); }
                set { SetValue(EllipseDiameterProperty, value); }
            }

            // Using a DependencyProperty as the backing store for EllipseDiameter.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty EllipseDiameterProperty =
                DependencyProperty.Register("EllipseDiameter", typeof(double), typeof(TemplateSettingValues), new PropertyMetadata(0D));

            public Thickness EllipseOffset
            {
                get { return (Thickness)GetValue(EllipseOffsetProperty); }
                set { SetValue(EllipseOffsetProperty, value); }
            }

            // Using a DependencyProperty as the backing store for EllipseOffset.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty EllipseOffsetProperty =
                DependencyProperty.Register("EllipseOffset", typeof(Thickness), typeof(TemplateSettingValues), new PropertyMetadata(new Thickness()));
        }
    }
}

Step 2

Now open App.xaml as we have to add some code there under <Application.Resources>. So the code will be

<Application.Resources>
    <local:LocalizedStrings xmlns:local="clr-[[Your app name space here]]" x:Key="LocalizedStrings"/>
    <Style TargetType="controls:ProgressRing">
        <Setter Property="Foreground" Value="{StaticResource PhoneAccentBrush}" />
        <Setter Property="IsHitTestVisible" Value="False" />
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="VerticalAlignment" Value="Center" />
        <Setter Property="MinHeight" Value="20" />
        <Setter Property="MinWidth" Value="20" />
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="controls:ProgressRing">
                    <Border x:Name="ProgressRingRoot" Background="{TemplateBinding Background}"
                BorderThickness="{TemplateBinding BorderThickness}"
                BorderBrush="{TemplateBinding BorderBrush}">
                        <Border.Resources>
                            <Style x:Key="ProgressRingEllipseStyle" TargetType="Ellipse">
                                <Setter Property="Opacity" Value="0" />
                                <Setter Property="HorizontalAlignment" Value="Left" />
                                <Setter Property="VerticalAlignment" Value="Top" />
                            </Style>
                        </Border.Resources>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="SizeStates">
                                <VisualState x:Name="Large">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Duration="0"
                                                            Storyboard.TargetName="SixthCircle"
                                                            Storyboard.TargetProperty="Visibility">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Small" />
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="ActiveStates">
                                <VisualState x:Name="Inactive" />
                                <VisualState x:Name="Active">
                                    <Storyboard RepeatBehavior="Forever">
                                        <ObjectAnimationUsingKeyFrames Duration="0"
                                                            Storyboard.TargetName="Ring"
                                                            Storyboard.TargetProperty="Visibility">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                Storyboard.TargetName="E1"
                                Storyboard.TargetProperty="Opacity"
                                BeginTime="0">
                                            <DiscreteDoubleKeyFrame KeyTime="0" Value="1" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.21" Value="1" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.22" Value="0" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.47" Value="0" />
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                Storyboard.TargetName="E2"
                                Storyboard.TargetProperty="Opacity"
                                BeginTime="00:00:00.167">
                                            <DiscreteDoubleKeyFrame KeyTime="0" Value="1" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.21" Value="1" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.22" Value="0" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.47" Value="0" />
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                Storyboard.TargetName="E3"
                                Storyboard.TargetProperty="Opacity"
                                BeginTime="00:00:00.334">
                                            <DiscreteDoubleKeyFrame KeyTime="0" Value="1" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.21" Value="1" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.22" Value="0" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.47" Value="0" />
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                Storyboard.TargetName="E4"
                                Storyboard.TargetProperty="Opacity"
                                BeginTime="00:00:00.501">
                                            <DiscreteDoubleKeyFrame KeyTime="0" Value="1" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.21" Value="1" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.22" Value="0" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.47" Value="0" />
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                Storyboard.TargetName="E5"
                                Storyboard.TargetProperty="Opacity"
                                BeginTime="00:00:00.668">
                                            <DiscreteDoubleKeyFrame KeyTime="0" Value="1" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.21" Value="1" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.22" Value="0" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.47" Value="0" />
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                Storyboard.TargetName="E6"
                                Storyboard.TargetProperty="Opacity"
                                BeginTime="00:00:00.835">
                                            <DiscreteDoubleKeyFrame KeyTime="0" Value="1" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.21" Value="1" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.22" Value="0" />
                                            <DiscreteDoubleKeyFrame KeyTime="0:0:3.47" Value="0" />
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                Storyboard.TargetName="E1R"
                                BeginTime="0"
                                Storyboard.TargetProperty="Angle">
                                            <SplineDoubleKeyFrame KeyTime="0" Value="-110" KeySpline="0.13,0.21,0.1,0.7"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:0.433" Value="10" KeySpline="0.02,0.33,0.38,0.77"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:1.2" Value="93"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:1.617" Value="205" KeySpline="0.57,0.17,0.95,0.75"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:2.017" Value="357" KeySpline="0,0.19,0.07,0.72"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:2.783" Value="439"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:3.217" Value="585" KeySpline="0,0,0.95,0.37"/>
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                Storyboard.TargetName="E2R"
                                BeginTime="00:00:00.167"
                                Storyboard.TargetProperty="Angle">
                                            <SplineDoubleKeyFrame KeyTime="0" Value="-116" KeySpline="0.13,0.21,0.1,0.7"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:0.433" Value="4" KeySpline="0.02,0.33,0.38,0.77"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:1.2" Value="87"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:1.617" Value="199" KeySpline="0.57,0.17,0.95,0.75"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:2.017" Value="351" KeySpline="0,0.19,0.07,0.72"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:2.783" Value="433"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:3.217" Value="579" KeySpline="0,0,0.95,0.37"/>
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                Storyboard.TargetName="E3R"
                                BeginTime="00:00:00.334"
                                Storyboard.TargetProperty="Angle">
                                            <SplineDoubleKeyFrame KeyTime="0" Value="-122" KeySpline="0.13,0.21,0.1,0.7"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:0.433" Value="-2" KeySpline="0.02,0.33,0.38,0.77"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:1.2" Value="81"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:1.617" Value="193" KeySpline="0.57,0.17,0.95,0.75"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:2.017" Value="345" KeySpline="0,0.19,0.07,0.72"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:2.783" Value="427"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:3.217" Value="573" KeySpline="0,0,0.95,0.37"/>
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                Storyboard.TargetName="E4R"
                                BeginTime="00:00:00.501"
                                Storyboard.TargetProperty="Angle">
                                            <SplineDoubleKeyFrame KeyTime="0" Value="-128" KeySpline="0.13,0.21,0.1,0.7"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:0.433" Value="-8" KeySpline="0.02,0.33,0.38,0.77"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:1.2" Value="75"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:1.617" Value="187" KeySpline="0.57,0.17,0.95,0.75"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:2.017" Value="339" KeySpline="0,0.19,0.07,0.72"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:2.783" Value="421"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:3.217" Value="567" KeySpline="0,0,0.95,0.37"/>
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                Storyboard.TargetName="E5R"
                                BeginTime="00:00:00.668"
                                Storyboard.TargetProperty="Angle">
                                            <SplineDoubleKeyFrame KeyTime="0" Value="-134" KeySpline="0.13,0.21,0.1,0.7"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:0.433" Value="-14" KeySpline="0.02,0.33,0.38,0.77"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:1.2" Value="69"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:1.617" Value="181" KeySpline="0.57,0.17,0.95,0.75"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:2.017" Value="331" KeySpline="0,0.19,0.07,0.72"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:2.783" Value="415"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:3.217" Value="561" KeySpline="0,0,0.95,0.37"/>
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                Storyboard.TargetName="E6R"
                                BeginTime="00:00:00.835"
                                Storyboard.TargetProperty="Angle">
                                            <SplineDoubleKeyFrame KeyTime="0" Value="-140" KeySpline="0.13,0.21,0.1,0.7"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:0.433" Value="-20" KeySpline="0.02,0.33,0.38,0.77"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:1.2" Value="63"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:1.617" Value="175" KeySpline="0.57,0.17,0.95,0.75"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:2.017" Value="325" KeySpline="0,0.19,0.07,0.72"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:2.783" Value="409"/>
                                            <SplineDoubleKeyFrame KeyTime="0:0:3.217" Value="555" KeySpline="0,0,0.95,0.37"/>
                                        </DoubleAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Grid x:Name="Ring"
                    Margin="{TemplateBinding Padding}"
                    MaxWidth="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.MaxSideLength}"
                    MaxHeight="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.MaxSideLength}"
                    Visibility="Collapsed"
                    RenderTransformOrigin=".5,.5"
                    FlowDirection="LeftToRight">
                            <Canvas RenderTransformOrigin=".5,.5">
                                <Canvas.RenderTransform>
                                    <RotateTransform x:Name="E1R" />
                                </Canvas.RenderTransform>
                                <Ellipse
                        x:Name="E1"
                        Style="{StaticResource ProgressRingEllipseStyle}"
                        Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"
                        Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"
                        Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseOffset}"
                        Fill="{TemplateBinding Foreground}"/>
                            </Canvas>
                            <Canvas RenderTransformOrigin=".5,.5">
                                <Canvas.RenderTransform>
                                    <RotateTransform x:Name="E2R" />
                                </Canvas.RenderTransform>
                                <Ellipse
                        x:Name="E2"
                        Style="{StaticResource ProgressRingEllipseStyle}"
                        Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"
                        Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"
                        Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseOffset}"
                        Fill="{TemplateBinding Foreground}"/>
                            </Canvas>
                            <Canvas RenderTransformOrigin=".5,.5">
                                <Canvas.RenderTransform>
                                    <RotateTransform x:Name="E3R" />
                                </Canvas.RenderTransform>
                                <Ellipse
                        x:Name="E3"
                        Style="{StaticResource ProgressRingEllipseStyle}"
                        Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"
                        Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"
                        Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseOffset}"
                        Fill="{TemplateBinding Foreground}"/>
                            </Canvas>
                            <Canvas RenderTransformOrigin=".5,.5">
                                <Canvas.RenderTransform>
                                    <RotateTransform x:Name="E4R" />
                                </Canvas.RenderTransform>
                                <Ellipse
                        x:Name="E4"
                        Style="{StaticResource ProgressRingEllipseStyle}"
                        Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"
                        Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"
                        Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseOffset}"
                        Fill="{TemplateBinding Foreground}"/>
                            </Canvas>
                            <Canvas RenderTransformOrigin=".5,.5">
                                <Canvas.RenderTransform>
                                    <RotateTransform x:Name="E5R" />
                                </Canvas.RenderTransform>
                                <Ellipse
                        x:Name="E5"
                        Style="{StaticResource ProgressRingEllipseStyle}"
                        Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"
                        Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"
                        Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseOffset}"
                        Fill="{TemplateBinding Foreground}"/>
                            </Canvas>
                            <Canvas RenderTransformOrigin=".5,.5"
                        Visibility="Collapsed"
                        x:Name="SixthCircle">
                                <Canvas.RenderTransform>
                                    <RotateTransform x:Name="E6R" />
                                </Canvas.RenderTransform>
                                <Ellipse
                        x:Name="E6"
                        Style="{StaticResource ProgressRingEllipseStyle}"
                        Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"
                        Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"
                        Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseOffset}"
                        Fill="{TemplateBinding Foreground}"/>
                            </Canvas>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Application.Resources>

Now you have added the control to your project now all you want is to call the control to the project.

Step 3

Now add the below code to add the control to the page.

<controls:ProgressRing 
	x:Name="ring" 
	Height="108" 
	IsActive="True" 
	Margin="187,332,185,0" 
	VerticalAlignment="Top" 
	Width="108" 
	Foreground="White" 
	RenderTransformOrigin="0.467,0.504">
</controls:ProgressRing>

Thats all 🙂 we are done.

Note : You may get some code errors while copy pasting the above codes, just rebuild the app, then automatically they will be removed. Please do not forget your project name space in the App.xaml file.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s