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!