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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|