WPF Radial Progress Bar with Radial Gradient

2020-07-11 08:44发布

With the help of this question and answer, I have managed to create a radial progress bar. This implements the arc drawing concept where the arc binds to the start and end angles.

The problem I have now is that I would like the progress bar to have radial gradient from the center of the arc. This gives the progress bar a "linear gradient" from the inside of the arc to the outside of the arc. I am trying to apply the radial gradient on the stroke of the arc (the Foreground property of the ProgressBar), but this applies the radial gradient at the center of the arc stroke, not the center of the arc object (as seen below).

40 percent arc

When the arc is at 100% (or anything above 75%), the center of the stroke is at the center of the arc, which produces the desired result.

100 percent arc 80 percent arc

How can I consistently adjust the center of the radial gradient to the center of the arc so that the desired gradient is applied at all fill percentages? Or is there a better solution/approach to this problem?

2条回答
孤傲高冷的网名
2楼-- · 2020-07-11 08:45

Since the RadialGradient you are using is most likely Relative, it will change its center depending on the actual size of the arc.

When the arc is at 75% or higher, the Geometry generated by Arc is at its maximum Width and Height and therefore stable and covering the entire control.

What you want to do is, draw the entire circle and mask out the parts that are outside of the "original" arc. Easies way to do that in your case is to replace the Arc.OnRender method with this:

Arc.cs

protected override void OnRender(DrawingContext drawingContext)
{
    // half the width and height of the Arc
    double radiusX = RenderSize.Width / 2;
    double radiusY = RenderSize.Height / 2;

    // the outlines of the "original" Arc geometry
    PathGeometry clip = GetArcGeometry().GetWidenedPathGeometry(
        new Pen(Stroke, StrokeThickness));

    // draw only in the area of the original arc
    drawingContext.PushClip(clip);
    drawingContext.DrawEllipse(Stroke, null, new Point(radiusX, radiusY), radiusX, radiusY);
    drawingContext.Pop();
}

Explanation

  1. Get the unmodified Geometry as calculated by the original code (GetArcGeometry)
  2. Extend it with the Pen that was previously used to draw the arc (GetWidenedPathGeometry)
  3. Instruct the DrawingContext to ignore anything outside of that area (Push(clip))
  4. Draw a full circle with the gradient (DrawEllipse)
  5. Instruct the DrawingContext to ignore the clip from now on (Pop)

Result

Result

查看更多
在下西门庆
3楼-- · 2020-07-11 08:45

A not so great, but easy to implement solution. You need to tweak the xaml so that instead of having an arc with the radial gradient increase in angle as the progress increases, have an arc with the required gradient behind an arc with gray colour. The gray arc reduces in angle to unveil the background arc with the correct radial gradient.

查看更多
登录 后发表回答