Skip to content

Instantly share code, notes, and snippets.

@JanDeDobbeleer
Created August 28, 2014 11:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JanDeDobbeleer/cee85f62839687f47bda to your computer and use it in GitHub Desktop.
Save JanDeDobbeleer/cee85f62839687f47bda to your computer and use it in GitHub Desktop.
Circular Progress Bar (Silverlight)
<UserControl x:Name="userControl" x:Class="Foo.Bar.CircularProgressBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480" d:DesignWidth="480">
<Grid>
<Path x:Name="pathRoot" Stroke="{Binding SegmentColor, ElementName=userControl}"
StrokeThickness="{Binding StrokeThickness, ElementName=userControl}" HorizontalAlignment="Left"
VerticalAlignment="Top">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure x:Name="pathFigure">
<PathFigure.Segments>
<PathSegmentCollection>
<ArcSegment x:Name="arcSegment" SweepDirection="Clockwise" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
</UserControl>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Fuo.Bar
{
public partial class CircularProgressBar : UserControl
{
public static readonly DependencyProperty PercentageProperty =
DependencyProperty.Register("Percentage", typeof (double), typeof (CircularProgressBar), new PropertyMetadata(65d, OnPercentageChanged));
// Using a DependencyProperty as the backing store for StrokeThickness. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register("StrokeThickness", typeof (int), typeof (CircularProgressBar), new PropertyMetadata(5));
// Using a DependencyProperty as the backing store for SegmentColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SegmentColorProperty =
DependencyProperty.Register("SegmentColor", typeof (Brush), typeof (CircularProgressBar), new PropertyMetadata(new SolidColorBrush(Colors.Yellow)));
// Using a DependencyProperty as the backing store for Radius. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RadiusProperty =
DependencyProperty.Register("Radius", typeof (int), typeof (CircularProgressBar), new PropertyMetadata(25, OnPropertyChanged));
// Using a DependencyProperty as the backing store for Angle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AngleProperty =
DependencyProperty.Register("Angle", typeof (double), typeof (CircularProgressBar), new PropertyMetadata(120d, OnPropertyChanged));
public CircularProgressBar()
{
InitializeComponent();
Angle = (Percentage*360)/100;
RenderArc();
}
public int Radius
{
get { return (int) GetValue(RadiusProperty); }
set { SetValue(RadiusProperty, value); }
}
public Brush SegmentColor
{
get { return (Brush) GetValue(SegmentColorProperty); }
set { SetValue(SegmentColorProperty, value); }
}
public int StrokeThickness
{
get { return (int) GetValue(StrokeThicknessProperty); }
set { SetValue(StrokeThicknessProperty, value); }
}
public double Percentage
{
get { return (double) GetValue(PercentageProperty); }
set { SetValue(PercentageProperty, value); }
}
public double Angle
{
get { return (double) GetValue(AngleProperty); }
set { SetValue(AngleProperty, value); }
}
// Using a DependencyProperty as the backing store for Percentage. This enables animation, styling, binding, etc...
private static void OnPercentageChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var circle = sender as CircularProgressBar;
circle.Angle = (circle.Percentage*360)/100;
}
private static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var circle = sender as CircularProgressBar;
circle.RenderArc();
}
public void RenderArc()
{
var startPoint = new Point(Radius, 0);
Point endPoint = ComputeCartesianCoordinate(Angle, Radius);
endPoint.X += Radius;
endPoint.Y += Radius;
pathRoot.Width = Radius*2 + StrokeThickness;
pathRoot.Height = Radius*2 + StrokeThickness;
pathRoot.Margin = new Thickness(StrokeThickness, StrokeThickness, 0, 0);
bool largeArc = Angle > 180.0;
var outerArcSize = new Size(Radius, Radius);
pathFigure.StartPoint = startPoint;
if (startPoint.X == Math.Round(endPoint.X) && startPoint.Y == Math.Round(endPoint.Y))
endPoint.X -= 0.01;
arcSegment.Point = endPoint;
arcSegment.Size = outerArcSize;
arcSegment.IsLargeArc = largeArc;
}
private Point ComputeCartesianCoordinate(double angle, double radius)
{
// convert to radians
double angleRad = (Math.PI/180.0)*(angle - 90);
double x = radius*Math.Cos(angleRad);
double y = radius*Math.Sin(angleRad);
return new Point(x, y);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment