Validate and Restrict Connections in a Diagram WPF

Connectors play an important role in a diagram. They visually indicate the relationship between two objects. There are several restrictions you can make when you set a connection, based on the kind of diagram you use. For example, you may want to restrict a flow in a specific direction, or you may not want to connect an object more than once. In this blog, let’s see how to impose such restrictions in diagram. 

I assume that you have some basic knowledge of diagram with nodes, connectors, and ports. This blog is written based on diagram for the WPF platform, but similar functionality is also available in other platforms. If you are new to the diagram component, please refer to the Getting Started section of our help documentation.

If you are trying a logic gate diagram: 

  • Nodes represent the gates.
  • Ports represent the ‘in’ and ‘out’ pins of gates.
  • A connector represents a flow or wire connecting pins.

Default connection behavior

By default, diagram does not enforce any rules, and allows connections anywhere, any number of times: 

  • Connectors can be left disconnected from objects, just by specifying the source and target point.
  • Connectors can be connected between nodes.
  • Connectors can be connected between ports (a specific point on a node or connector).
  • A connector has two ends; each end can take part in any of the above three.

When the cursor is over a valid object to make a connection, you will see following visual effects:

  • A green rectangle indicator on the target object.
  • An animation focusing the target object.
  • The cursor turns into a cross cursor.

When the cursor is over an object that is restricted, a green highlighter will not be visible and animation will not take place.

Restrictions

Restrict to connect to only ports (not to nodes)

If you want to connect only between ports and not between nodes, remove connectable capabilities from NodeContraints and set PortConstraints to all allow connections, as shown in the following.

Restrict connecting to only ports (not to nodes)

Resource

<syncfusion:NodeConstraints x:Key="disableConnect">

Selectable, Draggable, Resizable, Rotatable,InheritPortVisibility

</syncfusion:NodeConstraints>

<syncfusion:PortConstraints x:Key="enableConnect">

InheritPortVisibility, Connectable

</syncfusion:PortConstraints>

Node and Port constraints

<local:NodeVM Shape="{StaticResource AndGate}"

              Constraints="{StaticResource disableConnect}"

              OffsetX="100" OffsetY="100"

              UnitWidth="70" UnitHeight="50">

    <local:NodeVM.Ports>

        <syncfusion:PortCollection>

            <local:PortVM NodeOffsetX="0"

NodeOffsetY="0.2"

Constraints="{StaticResource enableConnect}" />

        </syncfusion:PortCollection>

    </local:NodeVM.Ports>

</local:NodeVM>

<local:NodeVM Shape="{StaticResource AndGate}"

                Constraints="{StaticResource disableConnect}"

                OffsetX="100" OffsetY="100"

                UnitWidth="70" UnitHeight="50">

    <local:NodeVM.Ports>

        <syncfusion:PortCollection>

            <local:PortVM NodeOffsetX="0"

NodeOffsetY="0.2"

Constraints="{StaticResource enableConnect}" />

        </syncfusion:PortCollection>

    </local:NodeVM.Ports>

</local:NodeVM>

Restrict in/out connection

You can validate the direction of the connection by specifying InConnect or OutConnect to PortConstraints as shown in the following.

Restrict in/out connections

Resources

<syncfusion:NodeConstraints x:Key="disableConnect">

Selectable, Draggable, Resizable, Rotatable, InheritPortVisibility

</syncfusion:NodeConstraints>

<syncfusion:PortConstraints x:Key="enableConnect">

InheritPortVisibility, Connectable

</syncfusion:PortConstraints>

<syncfusion:PortConstraints x:Key="enableInConnect">

InheritPortVisibility, InConnect

</syncfusion:PortConstraints>

<syncfusion:PortConstraints x:Key="enableOutConnect">

InheritPortVisibility, OutConnect

</syncfusion:PortConstraints>


Port constraints for in and out connections

<local:NodeVM Shape="{StaticResource AndGate}"

                Constraints="{StaticResource disableConnect}"

                OffsetX="100" OffsetY="100"

                UnitWidth="70" UnitHeight="50">

    <local:NodeVM.Ports>

        <syncfusion:PortCollection>

            <local:PortVM NodeOffsetX="0" NodeOffsetY="0.2"

Constraints="{StaticResource enableInConnect}" />

            <local:PortVM NodeOffsetX="0" NodeOffsetY="0.8"

Constraints="{StaticResource enableInConnect}"/>

            <local:PortVM NodeOffsetX="1" NodeOffsetY="0.5"

Constraints="{StaticResource enableOutConnect}"/>

        </syncfusion:PortCollection>

    </local:NodeVM.Ports>

</local:NodeVM>

Restrict number of connections

You can restrict the number of connections that can be connected to a port by overriding methods as shown in the code example.

Restrict number of connections

public bool CanCreateConnection(IConnector ignore)
{
    var info = this.Info as INodePortInfo;
    if (info.Connectors != null)
    {
        var count = info.Connectors.Where(c => c != ignore).Count();

        // Validate number of connections.
        if (MaxConnection >= 0 && count >= MaxConnection)
        {
            return false;
        }
    }
    else if(MaxConnection == 0)
    {
        return false;
    }
    return true;
}
public class CustomDiagram : SfDiagram
{
    // Validate and choose required tool.
    protected override void SetTool(SetToolArgs args)
    {
        base.SetTool(args);
        if(args.Source is IPort)
        {
            args.Action = ActiveTool.Draw;
        }

        if (args.Source is PortVM && args.Action == ActiveTool.Draw)
        {
            var port = args.Source as PortVM;
            if (!port.CanCreateConnection(null))
            {
                args.Action = ActiveTool.None;
            }
        }
    }

    // Validate the connection when connector endpoints are dragged.
    protected override void ValidateConnection(ConnectionParameter args)
    {
        if(args.TargetPort is PortVM)
        {
            var port = args.TargetPort as PortVM;
            if (!port.CanCreateConnection(args.Connector as IConnector))
            {
                args.TargetPort = null;
            }
        }
        base.ValidateConnection(args);
    }
}

Customizing visual effects

  

Show ports always

To show ports always, irrespective of any of their constraints or mouse-over state, set PortVisibility as Visible.

diagram.PortVisibility = PortVisibility.Visible;

Show ports only on mouse-over

To show ports only mouse is over the node or near the port, set PortVisibility as MouseOver.

diagram.PortVisibility = PortVisibility.MouseOver;

Show only valid ports during connection

Set PortVisibility as ValidConnection to show ports only when the cursor is over a node and only when validation is passed. That is, if a port does not pass the validation, it will stay hidden.

diagram.PortVisibility = PortVisibility.ValidConnection;

Hide animation during connection

You can hide the animation that indicates connection by applying a null template for RunTimeConnectionIndicator.

 

You can download the sample that demonstrates port validation and visual effects at ConnectionValidation.

Summary

In this post, you can see how connections to ports and nodes can be restricted. Likewise, you can also enforce your business constraints. For example, in a class diagram, you can make the following restrictions:

  • A class object cannot have more than one base class.
  • An interface object should not derive a class object.
  • A struct object cannot have any base struct or class object.

There are many more port options to explore. To explore ports more, please refer to our help documentation on Ports.

If you’re already a Syncfusion user, you can download the product setup here. If you’re not yet a Syncfusion user, you can download a free, 30-day trial here.

If you have any questions or require clarification about these features, please let us know in the comments below. You can also contact us through our support forum or Direct-Trac. We are happy to assist you!

Jegan R

Jegan R is a Product Manager in Syncfusion. He is good in WPF control development. He worked for Diagram component and currently working for Tools Components.