如何实现带指定线性渐变画刷的WPF环形进度条
WPF固定色段环形进度条实现方案
核心思路
直接给进度圆弧绑定线性渐变会导致渐变随当前进度长度拉伸,低进度下就会提前出现后续色段,不符合需求。正确实现逻辑如下:
- 将给定的线性渐变画刷的绘制范围固定为整个环形控件的外接矩形,不跟随进度圆弧的路径长度缩放
- 使用
Path搭配ArcSegment绘制环形,通过依赖属性绑定进度值,动态计算圆弧终点坐标 - 仅渲染当前进度范围内的圆弧段,即可保证已绘制部分颜色固定,到达对应进度阈值才显示对应颜色
代码实现
1. 资源定义
先在窗口/控件资源中加入指定渐变和环形轨道底色:
<Window.Resources> <LinearGradientBrush x:Key="LinearGradientProgressBrush" StartPoint="0,0" EndPoint="1,1" MappingMode="RelativeToBoundingBox"> <GradientStop Color="Yellow" Offset="0"/> <GradientStop Color="Red" Offset="0.25"/> <GradientStop Color="Green" Offset="0.50"/> <GradientStop Color="Blue" Offset="0.75"/> </LinearGradientBrush> <SolidColorBrush x:Key="ProgressTrackBrush" Color="#E5E5E5" /> </Window.Resources>
2. 界面布局
用Grid叠加两层环形,底层为灰色轨道,上层为渐变进度条:
<Grid Width="200" Height="200" x:Name="ProgressContainer"> <!-- 底部环形轨道 --> <Path Stroke="{StaticResource ProgressTrackBrush}" StrokeThickness="12" Data="M 100 10 A 90 90 0 1 1 99.9 10" /> <!-- 渐变进度圆弧 --> <Path x:Name="ProgressArc" Stroke="{StaticResource LinearGradientProgressBrush}" StrokeThickness="12" StrokeStartLineCap="Round" StrokeEndLineCap="Round" /> </Grid>
3. 后台逻辑
添加进度依赖属性,进度变更时动态计算圆弧路径:
public partial class MainWindow : Window { public double Progress { get => (double)GetValue(ProgressProperty); set => SetValue(ProgressProperty, value); } public static readonly DependencyProperty ProgressProperty = DependencyProperty.Register(nameof(Progress), typeof(double), typeof(MainWindow), new PropertyMetadata(0.0, OnProgressChanged)); // 环形参数,和界面尺寸对应 private const double RingRadius = 90; private const double CenterX = 100; private const double CenterY = 100; private static void OnProgressChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var host = d as MainWindow; var progress = Math.Clamp((double)e.NewValue, 0, 1); host.UpdateArc(progress); } private void UpdateArc(double progress) { // 角度换算:WPF中0度对应3点钟方向,减去90度将起点移到12点钟方向 double angle = progress * 360 - 90; double endX = CenterX + RingRadius * Math.Cos(angle * Math.PI / 180); double endY = CenterY + RingRadius * Math.Sin(angle * Math.PI / 180); bool isLargeArc = progress >= 0.5; // 构造当前进度对应的圆弧路径 ProgressArc.Data = Geometry.Parse( $"M {CenterX} {CenterY - RingRadius} A {RingRadius} {RingRadius} 0 {Convert.ToInt32(isLargeArc)} 1 {endX} {endY}" ); } public MainWindow() { InitializeComponent(); // 测试动画:4秒跑完一圈循环播放 var testAnim = new DoubleAnimation(0, 1, TimeSpan.FromSeconds(4)) { RepeatBehavior = RepeatBehavior.Forever }; BeginAnimation(ProgressProperty, testAnim); } }
效果说明
- 进度0~25%区间:圆弧从黄色平滑过渡到红色,已绘制段颜色固定
- 进度25%~50%区间:圆弧终点从红色过渡到绿色,前25%段黄-红渐变保持不变
- 进度50%~75%区间:圆弧终点从绿色过渡到蓝色,前50%段颜色完全固定
- 进度达到75%后才会出现蓝色段,完全匹配需求
如果需要调整环形尺寸、粗细,同步修改界面中Grid的宽高、Path的StrokeThickness,以及后台代码中
RingRadius、CenterX、CenterY参数即可。
内容的提问来源于stack exchange,提问作者chuckp
相关产品推荐
相关产品推荐

