wpf wpf-controls grid lines connector

line wpf



Cómo dibujar líneas de conexión entre dos controles en una cuadrícula WPF (1)

Estoy creando controles (botón decir) en una cuadrícula. Quiero crear una línea de conexión entre los controles. Digamos que haces mousedown en un botón y sueltas el mouse sobre otro botón. Esto debería dibujar una línea entre estos dos botones.

¿Puede alguien ayudarme o darme algunas ideas sobre cómo hacer esto?

¡Gracias por adelantado!


Estoy haciendo algo similar; aquí hay un resumen rápido de lo que hice:

Arrastrar y soltar

Para manejar el método de arrastrar y soltar entre controles hay bastante literatura en la web ( solo busca WPF arrastrando y soltando ). La implementación predeterminada de arrastrar y soltar es demasiado compleja, IMO, y terminamos usando algunos DP adjuntos para hacerlo más fácil ( similar a estos ). Básicamente, quieres un método de arrastre que se parece a esto:

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

En el objetivo, establezca AllowDrop en verdadero, luego agregue un evento a 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 ----- }

Dibujando la línea

¡Ahora para la parte difícil! Cada control expone una AnchorPoint DependencyProperty . Cuando se eleva el evento LayoutUpdated (es decir, cuando el control se mueve / cambia de tamaño / etc), el control vuelve a calcular su AnchorPoint. Cuando se agrega una línea de conexión, se une a DependencyProperties tanto de la fuente como de los AnchorPoints de destino. [ EDITAR : Como señaló Ray Burns en los comentarios, el lienzo y la cuadrícula solo necesitan estar en el mismo lugar; no necesitan estar en la misma jerarquía (aunque pueden serlo)]

Para actualizar la posición 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); }

Para crear la clase de línea (también se puede hacer en 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 }; } }

Si quieres ser mucho más elegante, puedes usar un MultiValueBinding en el origen y el destino y agregar un convertidor que cree el PathGeometry. Aquí hay un ejemplo de GraphSharp. Con este método, puede agregar flechas al final de la línea, usar curvas Bezier para que se vea más natural, enrutar la línea alrededor de otros controles ( aunque esto podría ser más difícil de lo que parece ), etc., etc.

Ver también