183 lines
6.1 KiB
C#
183 lines
6.1 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|