using Avalonia; using Avalonia.Controls; using Avalonia.Media; using Avalonia.Threading; using System; namespace YZWater.Avalonia.Controls; /// /// 管道控件 - 模拟 PipeLine /// public class PipeLineControl : Control { public static readonly StyledProperty IsFlowProperty = AvaloniaProperty.Register(nameof(IsFlow), false); public static readonly StyledProperty FlowSpeedProperty = AvaloniaProperty.Register(nameof(FlowSpeed), 1.0); public static readonly StyledProperty PipeColorProperty = AvaloniaProperty.Register(nameof(PipeColor), new SolidColorBrush(Color.Parse("#4CAF50"))); public static readonly StyledProperty WaterColorProperty = AvaloniaProperty.Register(nameof(WaterColor), new SolidColorBrush(Color.Parse("#2196F3"))); public static readonly StyledProperty PipeWidthProperty = AvaloniaProperty.Register(nameof(PipeWidth), 20.0); public static readonly StyledProperty IsHorizontalProperty = AvaloniaProperty.Register(nameof(IsHorizontal), true); public bool IsFlow { get => GetValue(IsFlowProperty); set => SetValue(IsFlowProperty, value); } public double FlowSpeed { get => GetValue(FlowSpeedProperty); set => SetValue(FlowSpeedProperty, value); } public IBrush PipeColor { get => GetValue(PipeColorProperty); set => SetValue(PipeColorProperty, value); } public IBrush WaterColor { get => GetValue(WaterColorProperty); set => SetValue(WaterColorProperty, value); } public double PipeWidth { get => GetValue(PipeWidthProperty); set => SetValue(PipeWidthProperty, value); } public bool IsHorizontal { get => GetValue(IsHorizontalProperty); set => SetValue(IsHorizontalProperty, value); } private double _flowOffset = 0; private IDisposable? _timerSubscription; static PipeLineControl() { AffectsRender(IsFlowProperty, FlowSpeedProperty, PipeColorProperty, WaterColorProperty, PipeWidthProperty, IsHorizontalProperty); } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); if (IsFlow) { StartAnimation(); } } protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { base.OnDetachedFromVisualTree(e); StopAnimation(); } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); if (change.Property == IsFlowProperty) { if (IsFlow) { StartAnimation(); } else { StopAnimation(); _flowOffset = 0; } } } private void StartAnimation() { StopAnimation(); _timerSubscription = DispatcherTimer.Run(() => { _flowOffset += FlowSpeed; if (_flowOffset >= 20) _flowOffset -= 20; InvalidateVisual(); return true; // 继续运行 }, TimeSpan.FromMilliseconds(50)); } private void StopAnimation() { _timerSubscription?.Dispose(); _timerSubscription = null; } public override void Render(DrawingContext context) { base.Render(context); var bounds = new Rect(Bounds.Size); var pipeWidth = PipeWidth; if (IsHorizontal) { // 绘制水平管道 var pipeRect = new Rect(0, (bounds.Height - pipeWidth) / 2, bounds.Width, pipeWidth); context.DrawRectangle(PipeColor, null, pipeRect); // 绘制流动效果 if (IsFlow) { var dashPen = new Pen(WaterColor, pipeWidth * 0.6, new DashStyle(new double[] { 8, 12 }, _flowOffset)); var y = bounds.Height / 2; context.DrawLine(dashPen, new Point(0, y), new Point(bounds.Width, y)); } } else { // 绘制垂直管道 var pipeRect = new Rect((bounds.Width - pipeWidth) / 2, 0, pipeWidth, bounds.Height); context.DrawRectangle(PipeColor, null, pipeRect); // 绘制流动效果 if (IsFlow) { var dashPen = new Pen(WaterColor, pipeWidth * 0.6, new DashStyle(new double[] { 8, 12 }, _flowOffset)); var x = bounds.Width / 2; context.DrawLine(dashPen, new Point(x, 0), new Point(x, bounds.Height)); } } } protected override Size MeasureOverride(Size availableSize) { return IsHorizontal ? new Size(80, 30) : new Size(30, 80); } }