Как потянуть соединительные линии между двумя средствами управления на сетке WPF

Я создаю средства управления (скажите что кнопка) на сетке. Я хочу создать соединительную линию между средствами управления. Скажите, что Вы Вы делаете mousedown на одной кнопке и выпускаете мышь по другой кнопке. Это должно чертить линию между этими двумя кнопками.

Кто-то может помочь мне или дать мне некоторое представление относительно того, как сделать это?

Заранее спасибо!

19
задан Scooby 12 May 2010 в 22:40
поделиться

1 ответ

Я делаю нечто подобное; Вот краткое изложение того, что я сделал:

Перетаскивание

Для обработки перетаскивания между элементами управления в Интернете довольно много литературы ( просто выполните поиск в WPF перетаскиванием ). Реализация перетаскивания по умолчанию слишком сложна, ИМО, и мы закончили тем, что использовали несколько подключенных DP, чтобы упростить ее ( аналогично этим ). По сути, вам нужен метод перетаскивания, который выглядит примерно так:

        private void onMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            UIElement element = sender as UIElement;
            if (element == null)
                return;
            DragDrop.DoDragDrop(element, new DataObject(this), DragDropEffects.Move);
        }

На цели установите для AllowDrop значение true, затем добавьте событие в Drop:

    private void onDrop(object sender, DragEventArgs args)
    {
        FrameworkElement elem = sender as FrameworkElement;
        if (null == elem)
            return;
        IDataObject data = args.Data;
        if (!data.GetDataPresent(typeof(GraphNode))
            return;
        GraphNode node = data.GetData(typeof(GraphNode)) as GraphNode;
        if(null == node)
            return;

        // ----- Actually do your stuff here -----
    }

Рисование линии

Теперь самое сложное! Каждый элемент управления предоставляет AnchorPoint DependencyProperty . Когда возникает событие LayoutUpdated (т. Е. Когда элемент управления перемещается / изменяет размер / и т. Д.), Элемент управления повторно вычисляет свою AnchorPoint. Когда добавляется соединительная линия, она привязывается к DependencyProperties как источника, так и назначения AnchorPoints. [ РЕДАКТИРОВАТЬ : Как отметил Рэй Бернс в комментариях, холст и сетка просто должны находиться в одном месте; они не обязательно должны быть в одной иерархии (хотя они могут быть)]

Для обновления позиции DP:

    private void onLayoutUpdated(object sender, EventArgs e)
    {
        Size size = RenderSize;
        Point ofs = new Point(size.Width / 2, isInput ? 0 : size.Height);
        AnchorPoint = TransformToVisual(node.canvas).Transform(ofs);
    }

Для создания класса линии (также можно сделать в XAML):

public sealed class GraphEdge : UserControl
{
    public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(Point), typeof(GraphEdge), new FrameworkPropertyMetadata(default(Point)));
    public Point Source { get { return (Point) this.GetValue(SourceProperty); } set { this.SetValue(SourceProperty, value); } }

    public static readonly DependencyProperty DestinationProperty = DependencyProperty.Register("Destination", typeof(Point), typeof(GraphEdge), new FrameworkPropertyMetadata(default(Point)));
    public Point Destination { get { return (Point) this.GetValue(DestinationProperty); } set { this.SetValue(DestinationProperty, value); } }

    public GraphEdge()
    {
        LineSegment segment = new LineSegment(default(Point), true);
        PathFigure figure = new PathFigure(default(Point), new[] { segment }, false);
        PathGeometry geometry = new PathGeometry(new[] { figure });
        BindingBase sourceBinding = new Binding {Source = this, Path = new PropertyPath(SourceProperty)};
        BindingBase destinationBinding = new Binding { Source = this, Path = new PropertyPath(DestinationProperty) };
        BindingOperations.SetBinding(figure, PathFigure.StartPointProperty, sourceBinding);
        BindingOperations.SetBinding(segment, LineSegment.PointProperty, destinationBinding);
        Content = new Path 
        {
            Data = geometry,
            StrokeThickness = 5,
            Stroke = Brushes.White,
            MinWidth = 1,
            MinHeight = 1
        };
    }
}

Если вы хотите получить намного больше, вы можете использовать MultiValueBinding для источника и назначения и добавить преобразователь, который создает PathGeometry. Вот пример из GraphSharp. Используя этот метод, вы можете добавить стрелки в конец линии, использовать кривые Безье, чтобы она выглядела более естественно, провести линию вокруг других элементов управления ( хотя это может быть сложнее, чем кажется ) и т. д. и т. д.


См. также

44
ответ дан 30 November 2019 в 03:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: