In one project I’m working on for a few months now I got the request to show progress bar in the form of circle – empty circle would mean 0%, and filled circle stands for 100%. It seemed like and interesting challenge, so I think I’ve found the simplest solution to the problem.
Let’s build it together…
First of all, we need a Path element with one ArcSegment and one LineSegment:
It will draw something like this – StartPoint is on the right, (A), ArcSegment draws half a circle to get to the point B, LineSegments goes to circle center C and since we have set parameter IsClosed to true, it draws another LineSegment to close the drawing in the point A, even if we didn’t write it explicitly.
We will bind this circular progress bar to a slider, as this is the simplest way to show how it works. You can, obviously, bind this to something else – the important thing is to get a value between 0 and 1 (0% – 100%).
This is the base that we need to have defined in XAML – the rest of the work will be done from code behind. We have named ArcSegment to be able to change its properties, namely Point and IsLargeArc.
First of all, we need circle radius and an angle that will represent a part of circle we want to show. Radius is equal to ArcSegment size (width or height, doesn’t matter), and the angle is full circle (360 degress or 2*PI) * percentage. When we have this two variables, you can use the following formula to calculate the point on the circle that corresponds to our percentage.
If the angle is more than PI (more than 180 degrees), we should set IsLargeArc to true, otherwise we will end up with this:
Unfortunately, were not quite there yet – there is a problem (I would dare to call it a bug) with 100% status, when the second point of ArcSegment is the same as the first one. In that case, even if you set IsLargeArc to true, you will not get a full circle:
So, we must use a hack – when a percentage reaches 100%, that means that the angle is equal to 2*PI, we will decrease the Y coordinate of the point by some small number, like 1/1000. By doing this, the second point will not be equal to the first one, but since the difference is very, very small, we will not be able to see it on the screen.
One last thing before the end – it is more common to see the circle fill from the top point, probably because that’s the way analog clock works. So, you can use rotation transform to fix this: