using Avalonia; using Avalonia.Controls; using Avalonia.Media; using Avalonia.VisualTree; namespace Plugin.Cowain.Wcs.Controls; public class RgvArrowDecorator : Decorator { public static readonly StyledProperty ArrowEndCanvasPointProperty = AvaloniaProperty.Register(nameof(ArrowEndCanvasPoint)); public Point ArrowEndCanvasPoint { get => GetValue(ArrowEndCanvasPointProperty); set => SetValue(ArrowEndCanvasPointProperty, value); } public static readonly StyledProperty ArrowBrushProperty = AvaloniaProperty.Register(nameof(ArrowBrush), Brushes.Red); public IBrush ArrowBrush { get => GetValue(ArrowBrushProperty); set => SetValue(ArrowBrushProperty, value); } public static readonly StyledProperty ArrowDirectionProperty = AvaloniaProperty.Register(nameof(ArrowDirection), false); public bool ArrowDirection { get => GetValue(ArrowDirectionProperty); set => SetValue(ArrowDirectionProperty, value); } public RgvArrowDecorator() { this.LayoutUpdated += (s, e) => this.InvalidateVisual(); ArrowEndCanvasPointProperty.Changed.AddClassHandler((b, e) => b.InvalidateVisual()); ArrowBrushProperty.Changed.AddClassHandler((b, e) => b.InvalidateVisual()); ArrowDirectionProperty.Changed.AddClassHandler((b, e) => b.InvalidateVisual()); } public override void Render(DrawingContext context) { base.Render(context); var start = new Point(Bounds.Width / 2, Bounds.Height / 2); var endCanvas = ArrowEndCanvasPoint; var canvas = this.FindAncestorOfType(); if (canvas == null) return; var transform = this.TransformToVisual(canvas); Point myLeftTop = default; if (transform != null) { if (transform is Matrix matrix) myLeftTop = matrix.Transform(new Point(0, 0)); } // 转换为本地坐标 var end = new Point(endCanvas.X - myLeftTop.X, endCanvas.Y - myLeftTop.Y); // 计算三段折线 double offset = 15; // 垂直偏移 bool isAbove = end.Y < start.Y; // 第一拐点:起点垂直偏移 var first = new Point(start.X, start.Y + (isAbove ? -offset : offset)); // 第二拐点:目标X,起点Y偏移 var second = new Point(end.X, end.Y + (isAbove ? offset : -offset)); // 终点:目标点 var last = new Point(end.X, end.Y); // 画三段折线 var pen = new Pen(ArrowBrush, 2); context.DrawLine(pen, start, first); context.DrawLine(pen, first, second); context.DrawLine(pen, second, last); // 画箭头头部 if (ArrowDirection) { DrawArrowHead(context, end, second, ArrowBrush); } else { DrawArrowHead(context, second, end, ArrowBrush); } } private void DrawArrowHead(DrawingContext context, Point from, Point to, IBrush brush) { // 箭头头部为V型 double arrowSize = 10; double angle = Math.Atan2(to.Y - from.Y, to.X - from.X); double leftAngle = angle + Math.PI / 6; double rightAngle = angle - Math.PI / 6; var left = new Point( to.X - arrowSize * Math.Cos(leftAngle), to.Y - arrowSize * Math.Sin(leftAngle)); var right = new Point( to.X - arrowSize * Math.Cos(rightAngle), to.Y - arrowSize * Math.Sin(rightAngle)); var pen = new Pen(brush, 2); context.DrawLine(pen, to, left); context.DrawLine(pen, to, right); } }