Как перерисовать линию на место перетаскивания библиотеки gong-wpf-dragdrop

Использую библиотеку gong-wpf-dragdrop для перетаскивания элементов. В место перетаскивания элемента отображается дефолтная линия, сероватого цвета и треугольники по бокам.

Можно ли как-то перерисовать линию, чтобы она была определенных размеров, цвета и т.п.

Как поменять цвет я знаю, но как отрисовать ее размер, убрать треугольники найти не могу.


Ответы (1 шт):

Автор решения: Voenkomat

Нашел как сделать свою линию. Нужен класс.

public class CustomInsertAdorner : DropTargetAdorner
{
    private double _animationOffset = 0;
    private bool _increasing = true;
    public CustomInsertAdorner(UIElement adornedElement, IDropInfo dropInfo) : base(adornedElement, dropInfo)
    {
        CompositionTarget.Rendering += OnRendering;
    }

    private void OnRendering(object sender, EventArgs e)
    {
        if (_increasing)
        {
            _animationOffset += 0.3;
            if (_animationOffset >= 3)
                _increasing = false;
        }
        else
        {
            _animationOffset -= 0.3;
            if (_animationOffset <= 0)
                _increasing = true;
        }

        InvalidateVisual();
    }

    protected override void OnRender(DrawingContext dc)
    {
        var items = DropInfo.VisualTarget as ItemsControl;
        if (items == null || items.Items.Count == 0)
            return;
        int index = DropInfo.InsertIndex;
        double y;
        if (index == 0)
        {
            var first = items.ItemContainerGenerator.ContainerFromIndex(0) as FrameworkElement;
            if (first != null)
            {
                var transform = first.TransformToVisual(AdornedElement);
                var pos = transform.Transform(new Point(0, 0));
                y = pos.Y;
            }
            else
            {
                y = 0;
            }
        }
        else if (index >= items.Items.Count)
        {
            var last = items.ItemContainerGenerator.ContainerFromIndex(items.Items.Count - 1) as FrameworkElement;
            if (last != null)
            {
                var transform = last.TransformToVisual(AdornedElement);
                var pos = transform.Transform(new Point(0, 0));
                y = pos.Y + last.ActualHeight;
            }
            else
            {
                y = items.RenderSize.Height;
            }
        }
        else
        {
            var container = items.ItemContainerGenerator.ContainerFromIndex(index) as FrameworkElement;
            if (container != null)
            {
                var transform = container.TransformToVisual(AdornedElement);
                var pos = transform.Transform(new Point(0, 0));
                y = pos.Y;
            }
            else
            {
                y = 0;
            }
        }

        DrawAnimatedLineWithBubble(dc, y, index, AdornedElement.RenderSize.Width);
    }

    private void DrawAnimatedLineWithBubble(DrawingContext dc, double y, int index, double width)
    {
        var pen = new Pen(Brushes.Red, 2 + _animationOffset)
        {
            DashStyle = DashStyles.Dash
        };
        dc.DrawLine(pen, new Point(0, y), new Point(width, y));
        string text = index.ToString();
        var ft = new FormattedText(text, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Segoe UI"), 12, Brushes.White, VisualTreeHelper.GetDpi(AdornedElement).PixelsPerDip);
        double bubbleRadius = Math.Max(ft.Width, ft.Height) + 6;
        double bubbleX = width - bubbleRadius - 5;
        double bubbleY = y - bubbleRadius / 2;
        dc.DrawEllipse(Brushes.Red, null, new Point(bubbleX + bubbleRadius / 2, bubbleY + bubbleRadius / 2), bubbleRadius / 2, bubbleRadius / 2);
        dc.DrawText(ft, new Point(bubbleX + bubbleRadius / 2 - ft.Width / 2, bubbleY + bubbleRadius / 2 - ft.Height / 2));
    }
}

Логику можно любую сделать, тут как бы пульсация

И нужен Хэндлер:

public class MyDragHandler : IDragSource, IDropTarget
{
    readonly Action<bool> _setDraggingState;
    public MyDragHandler()
    {
    }

    public MyDragHandler(Action<bool> setDraggingState) => _setDraggingState = setDraggingState;
    public bool CanStartDrag(IDragInfo dragInfo)
    {
        var src = Mouse.DirectlyOver as DependencyObject;
        var btn = FindParent<Button>(src);
        return btn?.Name == "DragButton";
    }

    public void StartDrag(IDragInfo dragInfo)
    {
        dragInfo.Data = dragInfo?.SourceItem;
        dragInfo.Effects = DragDropEffects.Move;
        _setDraggingState?.Invoke(true);
    }

    public void DragCancelled() => _setDraggingState?.Invoke(false);
    public void Dropped(IDropInfo dropInfo) => _setDraggingState?.Invoke(false);
    public void DragDropOperationFinished(DragDropEffects op, IDragInfo info) => _setDraggingState?.Invoke(false);
    public bool TryCatchOccurredException(Exception exception) => false;
    public void DragOver(IDropInfo dropInfo)
    {
        dropInfo.Effects = DragDropEffects.Move;
        dropInfo.DropTargetAdorner = typeof(CustomInsertAdorner);
    }

    public void Drop(IDropInfo dropInfo) => GongSolutions.Wpf.DragDrop.DragDrop.DefaultDropHandler.Drop(dropInfo);
    static T FindParent<T>(DependencyObject child)
        where T : DependencyObject
    {
        while (child != null)
        {
            if (child is T t)
                return t;
            child = VisualTreeHelper.GetParent(child);
        }

        return null;
    }
}

Определяем в ресурсах окна/uc

handler:MyDragHandler x:Key="MyDragHandler"/>

Хэндлер цепляем к своем контролу где лежат элементы так:

dd:DragDrop.DragHandler="{StaticResource MyDragHandler}"
dd:DragDrop.DropHandler="{StaticResource MyDragHandler}"
→ Ссылка