C00225155-02/C00225155/MegaRobo.C00225155/MegaRobo.C00225155App/MenuViews/Bottles/CircleProgress.cs

183 lines
6.1 KiB
C#
Raw Permalink Normal View History

2026-04-13 09:12:49 +00:00
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace MegaRobo.C00225155App.MenuViews.Bottles
{
public class CircleProgress : Control
{
static CircleProgress()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(CircleProgress),
new FrameworkPropertyMetadata(typeof(CircleProgress)));
}
#region
public double StrokeThickness
{
get => (double)GetValue(StrokeThicknessProperty);
set => SetValue(StrokeThicknessProperty, value);
}
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register("StrokeThickness", typeof(double), typeof(CircleProgress),
new PropertyMetadata(8.0, (d, e) =>
{
((CircleProgress)d).DrawBackgroundPath();
((CircleProgress)d).UpdateProgressPath();
}));
public double Progress
{
get => (double)GetValue(ProgressProperty);
set => SetValue(ProgressProperty, value);
}
public static readonly DependencyProperty ProgressProperty =
DependencyProperty.Register("Progress", typeof(double), typeof(CircleProgress),
new PropertyMetadata(0.0, OnProgressChanged));
private static void OnProgressChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((CircleProgress)d).UpdateProgressPath();
}
#endregion
private Path backgroundPath;
private Path progressPath;
private TextBlock percentageText;
public void ForceRefresh()
{
UpdateProgressPath();
DrawBackgroundPath();
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
backgroundPath = (Path)GetTemplateChild("PART_BackgroundPath");
progressPath = (Path)GetTemplateChild("PART_ProgressPath");
percentageText = (TextBlock)GetTemplateChild("PART_PercentageText");
DrawBackgroundPath();
UpdateProgressPath();
// 订阅 SizeChanged 事件,确保布局完成后重新绘制
SizeChanged += OnSizeChanged;
}
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
DrawBackgroundPath();
UpdateProgressPath();
}
//protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
//{
// base.OnRenderSizeChanged(sizeInfo);
// DrawBackgroundPath();
// UpdateProgressPath();
//}
private void DrawBackgroundPath()
{
if (backgroundPath == null)
{
Debug.WriteLine("backgroundPath is null");
return;
}
double strokeThickness = StrokeThickness;
double width = ActualWidth > 0 ? ActualWidth : 33;
double height = ActualHeight > 0 ? ActualHeight : 33;
//double radius = Math.Abs(Math.Min(width, height) / 2 - backgroundPath.StrokeThickness / 2);
double radius = Math.Max(0, Math.Min(width, height) / 2 - strokeThickness / 2);
double centerX = width / 2;
double centerY = height / 2;
EllipseGeometry geometry = new EllipseGeometry
{
Center = new Point(centerX, centerY),
RadiusX = radius,
RadiusY = radius
};
geometry.Freeze();
// 背景圈数据绑定到 backgroundPath
backgroundPath.Data = geometry;
}
private void UpdateProgressPath()
{
if (progressPath == null || percentageText == null) return;
double strokeThickness = StrokeThickness;
double width = ActualWidth > 0 ? ActualWidth : 33;
double height = ActualHeight > 0 ? ActualHeight : 33;
//double radius = Math.Abs(Math.Min(width, height) / 2 - progressPath.StrokeThickness / 2);
double radius = Math.Max(0, Math.Min(width, height) / 2 - strokeThickness / 2);
double centerX = width / 2;
double centerY = height / 2;
// 更新百分比文本
percentageText.Text = $"{Progress * 100:F0}%";
// 特殊处理0%和100%的情况
if (Progress >= 1.0)
{
// 100% - 使用EllipseGeometry绘制完整圆环
progressPath.Data = new EllipseGeometry
{
Center = new Point(centerX, centerY),
RadiusX = radius,
RadiusY = radius
};
return;
}
else if (Progress <= 0.0)
{
// 0% - 创建不可见的微小线段替代null
var geometry1 = new LineGeometry(
new Point(centerX, centerY - radius),
new Point(centerX, centerY - radius + 0.01));
progressPath.Data = geometry1;
return;
}
// 正常进度绘制 (0 < Progress < 1)
double angle = Progress * 360;
bool isLargeArc = angle > 180;
Point endPoint = new Point(
centerX + radius * Math.Sin(angle * Math.PI / 180),
centerY - radius * Math.Cos(angle * Math.PI / 180)
);
PathGeometry geometry = new PathGeometry();
PathFigure figure = new PathFigure
{
StartPoint = new Point(centerX, centerY - radius),
IsClosed = false
};
figure.Segments.Add(new ArcSegment
{
Point = endPoint,
Size = new Size(radius, radius),
IsLargeArc = isLargeArc,
SweepDirection = SweepDirection.Clockwise,
RotationAngle = 0
});
geometry.Figures.Add(figure);
progressPath.Data = geometry;
}
}
}