/// <summary> /// Configures custom port handling with the help of <see cref="ILookup"/>. /// </summary> /// <remarks> /// When a user interacts with edges and their endpoints, /// node.Lookup(IPortCandidateProvider) is called for the nodes in that graph, /// and the framework returns the implementation of IPortCandidateProvider which /// supplies the list of available ports. /// /// Instead of the default, we'll register a custom lookup for type IPortCandidateProvider. /// /// Note: we'll update this method in a future tutorial step to work with folding. /// </remarks> private void CustomizePortHandling() { // Sets auto cleanup to false, since we don't want to remove unoccupied ports. Graph.NodeDefaults.Ports.AutoCleanUp = false; // First we create a GraphDecorator from the IGraph. // GraphDecorator is a utility class that aids in decorating model items from a graph instance. // Here, we call NodeDecorator.PortCandidateProviderDecorator // to access the lookup decorator for ports - the thing we want to change. // One way to decorate the graph is to use the factory design pattern. // We set the factory to a lambda expression which // returns instances that implement the IPortCandidateProvider interface. // Here we can create a CompositePortCandidateProvider that combines various port candidate providers. // The ExistingPortsCandidateProvider provides port candidates at the locations of the already existing ports. // The NodeCenterPortCandidateProvider provides a single port candidate at the center of the node. // The ShapeGeometryPortCandidateProvider provides several port candidates based on the shape of the node. Graph.GetDecorator().NodeDecorator.PortCandidateProviderDecorator.SetFactory( node => PortCandidateProviders.Combine( PortCandidateProviders.FromExistingPorts(node), PortCandidateProviders.FromNodeCenter(node), PortCandidateProviders.FromShapeGeometry(node))); // To modify the existing lookup for a graph element, typically we decorate it with the help // of one of graph's Get...Decorator() extension methods, // which allows to dynamically insert custom implementations for the specified types. // Doing this can be seen as dynamically subclassing // the class in question (the INode implementation in this case), but only // for the node instances that live in the graph in question and then // overriding just their Lookup(Type) method. The only difference to traditional // subclassing is that you get the "this" passed in as a parameter. // Doing this more than once is like subclassing more and more, so the order matters. }
internal CustomPortCandidateProvider(INode node) { this.node = node; geometryPortCandidateProvider = PortCandidateProviders.Combine( PortCandidateProviders.FromNodeCenter(node), PortCandidateProviders.FromShapeGeometry(node)); }
/// <summary> /// Returns a central port candidate if the owner node of the source /// candidate is green, and an empty list otherwise. /// </summary> public override IEnumerable <IPortCandidate> GetTargetPortCandidates(IInputModeContext context, IPortCandidate source) { // Check if the source node is green if (Color.Green.Equals(source.Owner.Tag)) { return(PortCandidateProviders.FromNodeCenter(node).GetTargetPortCandidates(context, source)); } else { return(new IPortCandidate[0]); } }