In this post we show how to create diagram links via drag-and-drop operation from a NodeListView used as a palette. Since the NodeListView control can contain only DiagramNode objects, we will create a custom node shape representing a connector. Once the dummy connector node is created, the NodeCreated event handler will replace it with a DiagramLink. In addition, the handler will find nearby nodes and automatically connect the link to them.
Let’s start with a new WPF project. Add a reference to mindfusion.diagramming.dll, and add Diagram and NodeListView controls to the window:
<ScrollViewer Grid.Column="0" Focusable="False" HorizontalScrollBarVisibility="Visible"> <diag:Diagram x:Name="diagram" AllowDrop="True" NodeCreated="OnNodeCreated" NodeModified="OnNodeModified"> </diag:Diagram> </ScrollViewer> <diag:NodeListView x:Name="nodeList" Grid.Column="1"> </diag:NodeListView>
In the Window constructor, create a custom node shape that will represent connectors:
var connectorShape = new Shape( null, // no borders new[] // decorations { new LineTemplate(10, 10, 10, 50), new LineTemplate(10, 50, 90, 50), new LineTemplate(90, 50, 90, 90) }, null, FillRule.Nonzero, "Connector");
Add a few nodes to the NodeListView, along with the dummy connector node:
var item1 = new ShapeNode { Shape = Shapes.Rectangle }; NodeListView.SetLabel(item1, "Activity"); nodeList.Items.Add(item1); var item2 = new ShapeNode { Shape = Shapes.Decision }; NodeListView.SetLabel(item2, "Decision"); nodeList.Items.Add(item2); var item3 = new ShapeNode { Shape = connectorShape }; NodeListView.SetLabel(item3, "Connector"); nodeList.Items.Add(item3);
In the NodeCreated event handler, check if the newly created node represents a connector, and replace it with a DiagramLink:
var node = e.Node as ShapeNode; if (node != null) { if (node.Shape.Id == "Connector") { // replace the dummy connector node with a DiagramLink var bounds = node.Bounds; diagram.Items.Remove(node); var link = diagram.Factory.CreateDiagramLink( bounds.TopLeft, bounds.BottomRight); link.SegmentCount = 3; link.Shape = LinkShape.Cascading; ConnectToNearbyNode(link); } ... }
Otherwise if it is a regular node, set its anchor points and connect it to nearby unconnected links, if there are any:
else { node.AnchorPattern = AnchorPattern.Decision2In2Out; node.Effects.Add(new GlassEffect()); ConnectToNearbyLink(node); }
The ConnectToNearbyNode method uses a LINQ query to find nodes in the vicinity of the link’s start or end point. If one is found at a distance shorter than 120 points, it is set as the link’s Origin or Destination.
private void ConnectToNearbyNode(DiagramLink link) { // connect to a nearby origin node var origin = diagram.Nodes.OrderBy(n => Utilities.Distance(n.GetCenter(), link.StartPoint)).FirstOrDefault(); if (origin != null) { var distance = Utilities.Distance(origin.GetCenter(), link.StartPoint); if (distance < 120) { link.Origin = origin; link.Route(); } } // connect to a nearby destination node var destination = diagram.Nodes.Where(n => n != origin).OrderBy(n => Utilities.Distance(n.GetCenter(), link.EndPoint)).FirstOrDefault(); if (destination != null) { var distance = Utilities.Distance(destination.GetCenter(), link.EndPoint); if (distance < 120) { link.Destination = destination; link.Route(); } } }
Similarly, the ConnectToNearbyLink method finds a nearby unconnected link and sets the specified node as the link’s Origin or Destination.
private void ConnectToNearbyLink(DiagramNode node) { var outLink = diagram.Links.Where(l => l.Origin is DummyNode).OrderBy(l => Utilities.Distance(node.GetCenter(), l.StartPoint)).FirstOrDefault(); if (outLink != null) { var distance = Utilities.Distance(node.GetCenter(), outLink.StartPoint); if (distance < 90) { outLink.Origin = node; outLink.Route(); return; } } var inLink = diagram.Links.Where(l => l.Destination is DummyNode).OrderBy(l => Utilities.Distance(node.GetCenter(), l.EndPoint)).FirstOrDefault(); if (inLink != null) { var distance = Utilities.Distance(node.GetCenter(), inLink.EndPoint); if (distance < 90) { inLink.Destination = node; inLink.Route(); return; } } }
The result of several drag and drop operation is displayed below.
The complete sample project is available for download here:
https://mindfusion.eu/_samples/LinkDragDrop.zip
Enjoy!