public void AddToGraph(VisualPortGraphNode source, VisualPortGraphNode destination, Port sourcePort, Port destinationPort) { if (source == null) { return; } source.GetPort(sourcePort.Name, condition: p => !p.IsInputPort); if (destination != null && destinationPort == null) { // Select matching port on destination destinationPort = destination.GetPort(sourcePort.Type, byMatchingType: true, condition: p => p.IsInputPort) ?? destination.Ports.FirstOrDefault(p => p.IsInputPort); } var sourcePositionHandler = new Action <string, Port, IPortConnection>((nodeId, port, connection) => { var node = Graph.GetNode(nodeId); if (node != null) { var portRender = node.PortRenders[port.Name]; var position = portRender.TranslatePoint(new Point(0, 0), node.Render); position.X += node.PositionX + portRender.ActualWidth; position.Y += node.PositionY + portRender.ActualHeight / 2 + connection.SourcePort.ConnectionIds.IndexOf(connection.Id) * 5 - connection.SourcePort.ConnectionIds.Count * 5; connection.SourcePosition = position; } }); var destinationPositionHandler = new Action <string, Port, IPortConnection>((nodeId, port, connection) => { var node = Graph.GetNode(nodeId); if (node != null) { FrameworkElement portRender; if (node.PortRenders.ContainsKey(port.Name)) { portRender = node.PortRenders[port.Name]; } else { portRender = node.PortRenders.Values.First(); } var position = portRender.TranslatePoint(new Point(0, 0), node.Render); position.X += node.PositionX; position.Y += node.PositionY + portRender.ActualHeight / 2; connection.DestinationPosition = position; } }); var newConnection = new PortGraphConnection() { Graph = Graph, StateTransition = StateTransition, UndoHistory = UndoHistory, SourceId = source.Id, DestinationId = destination?.Id ?? "", SourcePort = sourcePort, DestinationPort = destinationPort ?? null }; newConnection.InitialiseRender(); newConnection.SourcePositionHandler = sourcePositionHandler; newConnection.DestinationPositionHandler = destinationPositionHandler; newConnection.Validate(); // The following should change to accomodate manually-set positions if (sourcePort != null && !sourcePort.ConnectionIds.Contains(newConnection.Id)) { sourcePort.ConnectionIds.Add(newConnection.Id); } if (destinationPort != null && destinationPort.ConnectionIds.Contains(newConnection.Id)) { destinationPort.ConnectionIds.Add(newConnection.Id); } if (source != null) { source.RefreshPortUI(); } if (destination != null) { destination.RefreshPortUI(); } // Add connection when wire is manually placed onto a new source or destination (source as VisualPortGraphNode).PortConnectionRequested += port => { var conn = Graph.GetConnection(Graph.GetSelectedConnectionId()); if (conn != null) { if (port.IsInputPort) { conn.ChangeDestination(source.Id, port); } else { conn.ChangeSource(source.Id, port); } } }; if (destination != null) { (destination as VisualPortGraphNode).PortConnectionRequested += port => { var conn = Graph.GetConnection(Graph.GetSelectedConnectionId()); if (conn != null) { if (port.IsInputPort) { conn.ChangeDestination(destination.Id, port); } else { conn.ChangeSource(destination.Id, port); } } StateTransition.Update(Enums.DiagramMode.Idle); }; } Graph.AddConnection(newConnection); newConnection.Render.Loaded += (sender, args) => renderLoaded?.Execute(); foreach (var transitionEventHandler in transitionEventHandlers) { transitionEventHandler.Sender = newConnection; } if (destination != null) { Graph.SelectNode(destination.Id); } if (connectionIdOutput != null) { connectionIdOutput.Data = newConnection.Id; } }