using Avalonia; using Avalonia.Controls; using Avalonia.Media; using Avalonia.Threading; using System; using System.Globalization; namespace YZWater.Avalonia.Controls; /// /// 泵控件 - 模拟 HslPumpOne(优化版) /// public class PumpControl : Control { public static readonly StyledProperty IsRunningProperty = AvaloniaProperty.Register(nameof(IsRunning), false); public static readonly StyledProperty SpeedProperty = AvaloniaProperty.Register(nameof(Speed), 0.0); public static readonly StyledProperty FrequencyProperty = AvaloniaProperty.Register(nameof(Frequency), 50.0); public static readonly StyledProperty TextProperty = AvaloniaProperty.Register(nameof(Text), string.Empty); public static readonly StyledProperty RunningColorProperty = AvaloniaProperty.Register(nameof(RunningColor), new SolidColorBrush(Color.Parse("#4CAF50"))); public static readonly StyledProperty StoppedColorProperty = AvaloniaProperty.Register(nameof(StoppedColor), new SolidColorBrush(Color.Parse("#607D8B"))); public static readonly StyledProperty FaultColorProperty = AvaloniaProperty.Register(nameof(FaultColor), new SolidColorBrush(Color.Parse("#F44336"))); public bool IsRunning { get => GetValue(IsRunningProperty); set => SetValue(IsRunningProperty, value); } public double Speed { get => GetValue(SpeedProperty); set => SetValue(SpeedProperty, value); } public double Frequency { get => GetValue(FrequencyProperty); set => SetValue(FrequencyProperty, value); } public string Text { get => GetValue(TextProperty); set => SetValue(TextProperty, value); } public IBrush RunningColor { get => GetValue(RunningColorProperty); set => SetValue(RunningColorProperty, value); } public IBrush StoppedColor { get => GetValue(StoppedColorProperty); set => SetValue(StoppedColorProperty, value); } public IBrush FaultColor { get => GetValue(FaultColorProperty); set => SetValue(FaultColorProperty, value); } private double _rotationAngle = 0; private IDisposable? _timerSubscription; static PumpControl() { AffectsRender(IsRunningProperty, SpeedProperty, FrequencyProperty, TextProperty, RunningColorProperty, StoppedColorProperty, FaultColorProperty); } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); if (IsRunning) { StartAnimation(); } } protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { base.OnDetachedFromVisualTree(e); StopAnimation(); } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); if (change.Property == IsRunningProperty) { if (IsRunning) { StartAnimation(); } else { StopAnimation(); _rotationAngle = 0; } InvalidateVisual(); } } private void StartAnimation() { StopAnimation(); _timerSubscription = DispatcherTimer.Run(() => { _rotationAngle += Frequency / 20.0; if (_rotationAngle >= 360) _rotationAngle -= 360; InvalidateVisual(); return true; }, TimeSpan.FromMilliseconds(30)); } private void StopAnimation() { _timerSubscription?.Dispose(); _timerSubscription = null; } public override void Render(DrawingContext context) { base.Render(context); var bounds = new Rect(Bounds.Size); var centerX = bounds.Width / 2; var centerY = bounds.Height / 2 - 5; var radius = Math.Min(bounds.Width, bounds.Height) / 2 - 15; var typeface = new Typeface("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold); // 确定状态颜色 var statusColor = IsRunning ? RunningColor : StoppedColor; var statusBrush = statusColor as SolidColorBrush ?? new SolidColorBrush(Colors.Gray); // 绘制外圈发光效果(运行时) if (IsRunning) { var glowBrush = new SolidColorBrush(statusBrush.Color, 0.2); context.DrawEllipse(glowBrush, null, new Rect( centerX - radius - 8, centerY - radius - 8, (radius + 8) * 2, (radius + 8) * 2)); } // 绘制外壳 var outerPen = new Pen(new SolidColorBrush(Color.Parse("#455A64")), 3); context.DrawEllipse(null, outerPen, new Rect( centerX - radius, centerY - radius, radius * 2, radius * 2)); // 绘制内部背景 var innerBg = new SolidColorBrush(Color.Parse("#1E272E")); context.DrawEllipse(innerBg, null, new Rect( centerX - radius + 3, centerY - radius + 3, (radius - 3) * 2, (radius - 3) * 2)); // 绘制泵叶片 var bladeCount = 6; var bladeLength = radius * 0.65; var bladeWidth = radius * 0.18; for (int i = 0; i < bladeCount; i++) { var angle = _rotationAngle + (360.0 / bladeCount) * i; var radians = angle * Math.PI / 180; var bladeX = centerX + Math.Cos(radians) * bladeLength * 0.5; var bladeY = centerY + Math.Sin(radians) * bladeLength * 0.5; // 绘制叶片(带渐变效果) var bladeBrush = new SolidColorBrush(IsRunning ? Color.FromArgb(200, statusBrush.Color.R, statusBrush.Color.G, statusBrush.Color.B) : Color.Parse("#546E7A")); var bladePath = new StreamGeometry(); using (var ctx = bladePath.Open()) { ctx.BeginFigure(new Point(bladeX - bladeWidth / 2, bladeY - bladeLength / 2), true); ctx.LineTo(new Point(bladeX + bladeWidth / 2, bladeY - bladeLength / 2)); ctx.LineTo(new Point(bladeX + bladeWidth / 2, bladeY + bladeLength / 2)); ctx.LineTo(new Point(bladeX - bladeWidth / 2, bladeY + bladeLength / 2)); ctx.EndFigure(true); } // 旋转叶片 - 使用矩阵变换 var rotationRadians = angle * Math.PI / 180; var cos = Math.Cos(rotationRadians); var sin = Math.Sin(rotationRadians); var transform = new Matrix(cos, sin, -sin, cos, bladeX - bladeX * cos + bladeY * sin, bladeY - bladeX * sin - bladeY * cos); using (context.PushTransform(transform)) { context.DrawGeometry(bladeBrush, null, bladePath); } } // 绘制中心圆(带渐变) var centerRadius = radius * 0.25; var centerBrush = new SolidColorBrush(IsRunning ? statusBrush.Color : Color.Parse("#455A64")); context.DrawEllipse(centerBrush, null, new Rect( centerX - centerRadius, centerY - centerRadius, centerRadius * 2, centerRadius * 2)); // 中心高光 var highlightBrush = new SolidColorBrush(Colors.White, 0.3); context.DrawEllipse(highlightBrush, null, new Rect( centerX - centerRadius * 0.5, centerY - centerRadius * 0.5, centerRadius, centerRadius)); // 绘制状态指示灯 var indicatorSize = 8; var indicatorX = bounds.Width - 20; var indicatorY = 10; var indicatorBrush = IsRunning ? new SolidColorBrush(Color.Parse("#4CAF50")) : new SolidColorBrush(Color.Parse("#78909C")); // 指示灯发光 if (IsRunning) { context.DrawEllipse(new SolidColorBrush(indicatorBrush.Color, 0.3), null, new Rect(indicatorX - 4, indicatorY - 4, 16, 16)); } context.DrawEllipse(indicatorBrush, null, new Rect(indicatorX, indicatorY, indicatorSize, indicatorSize)); // 绘制文字标签 if (!string.IsNullOrEmpty(Text)) { var textBrush = new SolidColorBrush(Colors.White); var text = new FormattedText(Text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, 11, textBrush); var textPoint = new Point( centerX - text.Width / 2, bounds.Bottom - text.Height - 5); context.DrawText(text, textPoint); } // 绘制频率显示 if (IsRunning) { var freqStr = $"{Frequency:F0}Hz"; var freqText = new FormattedText(freqStr, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 9, new SolidColorBrush(statusBrush.Color)); context.DrawText(freqText, new Point(centerX - freqText.Width / 2, centerY + radius + 5)); } } protected override Size MeasureOverride(Size availableSize) { return new Size(70, 80); } }