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
相关产品推荐
相关产品推荐

