You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF环形进度条:设置0%起点为左下角及拖拽调节实现

自定义WPF环形ProgressBar(左下角端点+拖拽调整)

核心问题修复:端点定位与进度显示

默认环形进度的起始角度为0°(右侧),要让0%/100%落在左下角,需将起始角度固定为270°(WPF坐标系中顺时针计算,对应左下位置),同时调整角度计算逻辑匹配该起始点,解决进度显示异常问题。

修复后的XAML代码

<UserControl x:Class="CustomRingProgressBar.RingProgressBar"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Width="200" Height="200">
    <Grid>
        <!-- 背景圆环 -->
        <Ellipse Stroke="#E0E0E0" StrokeThickness="10" Margin="10"/>
        <!-- 进度圆环 -->
        <Path x:Name="ProgressPath" Stroke="#2196F3" StrokeThickness="10" StrokeLineCap="Round">
            <Path.Data>
                <PathGeometry>
                    <PathFigure x:Name="ProgressFigure" StartPoint="100,190">
                        <ArcSegment x:Name="ProgressArc" Size="90,90" SweepDirection="Clockwise" IsLargeArc="False"/>
                    </PathFigure>
                </PathGeometry>
            </Path.Data>
        </Path>
        <!-- 拖拽调节小球 -->
        <Ellipse x:Name="DragThumb" Fill="#FF5722" Width="20" Height="20" Cursor="Hand"
                 MouseLeftButtonDown="DragThumb_MouseLeftButtonDown"
                 MouseMove="DragThumb_MouseMove"
                 MouseLeftButtonUp="DragThumb_MouseLeftButtonUp"/>
    </Grid>
</UserControl>

修复后的后台C#代码

using System;
using System.Windows;
using System.Windows.Controls;

namespace CustomRingProgressBar
{
    public partial class RingProgressBar : UserControl
    {
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(double), typeof(RingProgressBar),
                new PropertyMetadata(0.0, OnValueChanged));

        public double Value
        {
            get => (double)GetValue(ValueProperty);
            set => SetValue(ValueProperty, Math.Clamp(value, 0, 100));
        }

        private bool _isDragging;
        private readonly double _radius = 90;
        private readonly Point _center = new Point(100, 100);

        public RingProgressBar()
        {
            InitializeComponent();
            UpdateProgressArc();
        }

        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((RingProgressBar)d).UpdateProgressArc();
        }

        private void UpdateProgressArc()
        {
            // 0%对应270°,100%对应270°+360°=630°,按进度比例计算实际角度
            double angle = 270 + (Value / 100) * 360;
            double radians = angle * Math.PI / 180;

            // 计算圆弧终点坐标
            double x = _center.X + _radius * Math.Cos(radians);
            double y = _center.Y + _radius * Math.Sin(radians);

            // 更新圆弧参数与小球位置
            ProgressArc.Point = new Point(x, y);
            ProgressArc.IsLargeArc = Value > 50;
            Canvas.SetLeft(DragThumb, x - DragThumb.Width / 2);
            Canvas.SetTop(DragThumb, y - DragThumb.Height / 2);
        }

        #region 拖拽事件处理
        private void DragThumb_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            _isDragging = true;
            DragThumb.CaptureMouse();
        }

        private void DragThumb_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (!_isDragging) return;

            Point mousePos = e.GetPosition(this);
            double dx = mousePos.X - _center.X;
            double dy = mousePos.Y - _center.Y;
            double angle = Math.Atan2(dy, dx) * 180 / Math.PI;

            // 将左下到右侧的负角度转为正角度,统一为270°-630°范围
            if (angle < 270) angle += 360;
            Value = Math.Clamp((angle - 270) / 360 * 100, 0, 100);
        }

        private void DragThumb_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            _isDragging = false;
            DragThumb.ReleaseMouseCapture();
        }
        #endregion
    }
}

关键修复与实现说明

  • 端点定位:将PathFigure的StartPoint设为(100,190),对应控件左下角的圆弧起点,匹配270°起始角度。
  • 进度计算逻辑:以270°为基准,按进度比例累加角度,确保0%/100%均落在左下角,进度顺时针正常增长。
  • 大弧判断:当进度超过50%时设置IsLargeArc=true,避免圆弧显示为小弧导致的视觉异常。
  • 拖拽功能:通过鼠标事件捕获拖拽状态,计算鼠标与控件中心的夹角,转换为对应进度值,实时更新控件状态。

使用示例

<Window x:Class="CustomRingProgressBar.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CustomRingProgressBar"
        Title="RingProgressBar Demo" Height="450" Width="800">
    <Grid>
        <local:RingProgressBar Value="40" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>

内容的提问来源于stack exchange,提问作者wpf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 00:52:02