251 lines
8.0 KiB
C#
251 lines
8.0 KiB
C#
using System;
|
||
using System.ComponentModel;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Windows.Media;
|
||
using System.Windows.Shapes;
|
||
|
||
namespace MegaRobo.C00225155App.MenuViews.Bottles
|
||
{
|
||
/// <summary>
|
||
/// 预估CT指示器控件 - 显示环形进度条和中心CT值
|
||
/// </summary>
|
||
[TemplatePart(Name = "PART_BackgroundPath", Type = typeof(Path))]
|
||
[TemplatePart(Name = "PART_ProgressPath", Type = typeof(Path))]
|
||
[TemplatePart(Name = "PART_CTText", Type = typeof(TextBlock))]
|
||
public class CTIndicator : Control
|
||
{
|
||
static CTIndicator()
|
||
{
|
||
DefaultStyleKeyProperty.OverrideMetadata(typeof(CTIndicator),
|
||
new FrameworkPropertyMetadata(typeof(CTIndicator)));
|
||
}
|
||
|
||
#region 依赖属性
|
||
|
||
/// <summary>
|
||
/// 进度值 (0.0 - 1.0)
|
||
/// </summary>
|
||
public double Progress
|
||
{
|
||
get => (double)GetValue(ProgressProperty);
|
||
set => SetValue(ProgressProperty, value);
|
||
}
|
||
|
||
public static readonly DependencyProperty ProgressProperty =
|
||
DependencyProperty.Register("Progress", typeof(double), typeof(CTIndicator),
|
||
new PropertyMetadata(0.0, OnProgressChanged));
|
||
|
||
/// <summary>
|
||
/// CT值文本
|
||
/// </summary>
|
||
public string CTValue
|
||
{
|
||
get => (string)GetValue(CTValueProperty);
|
||
set => SetValue(CTValueProperty, value);
|
||
}
|
||
|
||
public static readonly DependencyProperty CTValueProperty =
|
||
DependencyProperty.Register("CTValue", typeof(string), typeof(CTIndicator),
|
||
new PropertyMetadata("0min"));
|
||
|
||
/// <summary>
|
||
/// 进度条颜色
|
||
/// </summary>
|
||
public Brush ProgressColor
|
||
{
|
||
get => (Brush)GetValue(ProgressColorProperty);
|
||
set => SetValue(ProgressColorProperty, value);
|
||
}
|
||
|
||
public static readonly DependencyProperty ProgressColorProperty =
|
||
DependencyProperty.Register("ProgressColor", typeof(Brush), typeof(CTIndicator),
|
||
new PropertyMetadata(Brushes.Green));
|
||
|
||
/// <summary>
|
||
/// 背景环颜色
|
||
/// </summary>
|
||
public Brush BackgroundColor
|
||
{
|
||
get => (Brush)GetValue(BackgroundColorProperty);
|
||
set => SetValue(BackgroundColorProperty, value);
|
||
}
|
||
|
||
public static readonly DependencyProperty BackgroundColorProperty =
|
||
DependencyProperty.Register("BackgroundColor", typeof(Brush), typeof(CTIndicator),
|
||
new PropertyMetadata(Brushes.LightGray));
|
||
|
||
/// <summary>
|
||
/// 文本颜色
|
||
/// </summary>
|
||
public Brush TextColor
|
||
{
|
||
get => (Brush)GetValue(TextColorProperty);
|
||
set => SetValue(TextColorProperty, value);
|
||
}
|
||
|
||
public static readonly DependencyProperty TextColorProperty =
|
||
DependencyProperty.Register("TextColor", typeof(Brush), typeof(CTIndicator),
|
||
new PropertyMetadata(Brushes.Black));
|
||
|
||
/// <summary>
|
||
/// 环厚度
|
||
/// </summary>
|
||
public double RingThickness
|
||
{
|
||
get => (double)GetValue(RingThicknessProperty);
|
||
set => SetValue(RingThicknessProperty, value);
|
||
}
|
||
|
||
public static readonly DependencyProperty RingThicknessProperty =
|
||
DependencyProperty.Register("RingThickness", typeof(double), typeof(CTIndicator),
|
||
new PropertyMetadata(6.0));
|
||
|
||
/// <summary>
|
||
/// 字体大小
|
||
/// </summary>
|
||
public double CTFontSize
|
||
{
|
||
get => (double)GetValue(CTFontSizeProperty);
|
||
set => SetValue(CTFontSizeProperty, value);
|
||
}
|
||
|
||
public static readonly DependencyProperty CTFontSizeProperty =
|
||
DependencyProperty.Register("CTFontSize", typeof(double), typeof(CTIndicator),
|
||
new PropertyMetadata(10.0));
|
||
|
||
#endregion
|
||
|
||
#region 模板部件
|
||
|
||
private Path _backgroundPath;
|
||
private Path _progressPath;
|
||
private TextBlock _ctText;
|
||
|
||
public void ForceRefresh()
|
||
{
|
||
UpdateProgressPath();
|
||
UpdateCTValueText(); // 新增:显式更新CTValue文本
|
||
}
|
||
|
||
public override void OnApplyTemplate()
|
||
{
|
||
base.OnApplyTemplate();
|
||
|
||
_backgroundPath = GetTemplateChild("PART_BackgroundPath") as Path;
|
||
_progressPath = GetTemplateChild("PART_ProgressPath") as Path;
|
||
_ctText = GetTemplateChild("PART_CTText") as TextBlock;
|
||
|
||
UpdateProgressPath();
|
||
UpdateCTValueText();
|
||
SizeChanged += OnSizeChanged;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 事件处理
|
||
|
||
private static void OnProgressChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
{
|
||
var indicator = (CTIndicator)d;
|
||
indicator.UpdateProgressPath();
|
||
}
|
||
|
||
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||
{
|
||
UpdateProgressPath();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 绘制逻辑
|
||
|
||
private void UpdateProgressPath()
|
||
{
|
||
if (_backgroundPath == null || _progressPath == null || _ctText == null)
|
||
return;
|
||
|
||
double width = ActualWidth > 0 ? ActualWidth : 33;
|
||
double height = ActualHeight > 0 ? ActualHeight : 33;
|
||
|
||
double ringThickness = RingThickness;
|
||
double radius = Math.Max(0, Math.Min(width, height) / 2 - ringThickness / 2);
|
||
double centerX = width / 2;
|
||
double centerY = height / 2;
|
||
|
||
// 更新背景环
|
||
_backgroundPath.StrokeThickness = ringThickness;
|
||
_backgroundPath.Data = new EllipseGeometry
|
||
{
|
||
Center = new Point(centerX, centerY),
|
||
RadiusX = radius,
|
||
RadiusY = radius
|
||
};
|
||
|
||
// 更新进度环
|
||
_progressPath.StrokeThickness = ringThickness;
|
||
_progressPath.Stroke = ProgressColor;
|
||
|
||
double angle = Progress * 360;
|
||
bool isLargeArc = angle > 180;
|
||
|
||
// 特殊处理0%和100%的情况
|
||
if (Progress >= 1.0)
|
||
{
|
||
_progressPath.Data = new EllipseGeometry
|
||
{
|
||
Center = new Point(centerX, centerY),
|
||
RadiusX = radius,
|
||
RadiusY = radius
|
||
};
|
||
}
|
||
else if (Progress <= 0.0)
|
||
{
|
||
// 创建不可见的微小线段
|
||
var geometry = new LineGeometry(
|
||
new Point(centerX, centerY - radius),
|
||
new Point(centerX, centerY - radius + 0.01));
|
||
_progressPath.Data = geometry;
|
||
}
|
||
else
|
||
{
|
||
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;
|
||
}
|
||
|
||
// 更新文本
|
||
_ctText.Text = CTValue;
|
||
_ctText.FontSize = CTFontSize;
|
||
_ctText.Foreground = TextColor;
|
||
}
|
||
|
||
private void UpdateCTValueText()
|
||
{
|
||
if (_ctText == null) return;
|
||
_ctText.Text = CTValue; // 确保文本与依赖属性同步
|
||
}
|
||
#endregion
|
||
}
|
||
}
|