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