Home » Blog

rounded header

WPF Diagramming: Connection validation and an API change

One important feature that some diagrams need is connection validation. That is, the ability to control which diagram nodes are allowed to be connected together. For example, you might want node A to be connectable only to node B. Or you may want to prevent start nodes being connected to end nodes. Many different diagrams will require their own unique connection validation which is why WPF Diagramming provides a way for you to customize this logic. The two interfaces that you need to consider when providing your own logic is the IDiagramConnectionBuilder and the IDiagramConnectionRelocator. The connection builder contains a method for building a connection and adding it to the diagram, and the relocator has a method for performing the connection relocation. Originally, custom connection validation would be taken place in your own implementations of these methods. A disadvantage of doing it this way is that the user interface is oblivious to this validation. Because of this, the user would only know if a connection can not be made between particular nodes after they let go of the mouse button and find that no connection is created. However, a recent modification to these two interfaces solves this issue. In this blog post we look at this modification that has been made, as well as how to provide your own connection validation logic to your applications.

Connection builder and connection relocator API change.

Both the IDiagramConnectionBuilder and the IDiagramConnectionRelocator now has an additional method that returns whether or not they are allowed to perform their respective actions. The new connection builder method is called CanCreateConnection which has the following parameters:

  • IDiagramModel. This is simply the diagram that the new connection is going to be added to.
  • IDiagramConnectionPoint. This is the connection point where the new connection is going to originate. Using the Connectable property on this connection point gives us access to the diagram node that the connection will be attached to.
  • ConnectionDropTarget. This is a new type of object that contains information about where the user is dragging the end of the connection to.

This method is also called in the situation where the user has just pressed the mouse button on a connection point thumb in preperation to create a connection. This allows you to provide connection validation logic that prevents certain types of connections being made on certain types of nodes. One thing to be aware of is that the ConnectionDropTarget parameter will be null to represent this situation.

The new connection relocator method is called CanRelocateConnection and contains all the parameters as previously mentioned as well as the IDiagramConnection that is being relocated. One thing to note is that the IDiagramConnectionPoint parameter is the connection point that the connection is still attached to, and the ConnectionDropTarget holds information about the end of the connection that the user is dragging.

Custom connection validation logic

Now that we know the basics, lets implement our own connection validation logic for a flow diagram to follow. Our logic will simply prevent any StartNode elements from being directly connected to an EndNode element. We want both our IDiagramConnectionBuilder and IDiagramConnectionRelocator implementations to share the same connection validation logic, so we can write it in a static method as follows:

public static class ConnectionValidationLogic
{
  public static bool ValidateConnection(IDiagramConnectionPoint connectionPoint, ConnectionDropTarget dropTarget)
  {
    bool canCreateConnection = true;
    if (dropTarget != null)
    {
      IDiagramConnectable source = connectionPoint.Connectable;
      IDiagramConnectable destination = dropTarget.Connectable;
      if (source is StartNode && destination is EndNode)
      {
        canCreateConnection = false;
      }
    }
    return canCreateConnection;
  }
}

For our validation logic we will only be interested in the source and destination of the connection. So the only parameters we need for this method is the IDiagramConnectionPoint and the ConnectionDropTarget object. As previously mentioned, the drop target object will be null in a special situation so we include a null check around the rest of our logic. We can aquire the source item of the connection by using the Connectable property on the connection point, and the destination item can be obtained with dropTarget.Connectable. Then all our logic needs to do is return false if the source is a StartNode and the destination is an EndNode. Later when we give this logic to the diagram, we will get the following results:

Here on the left we can see the user is creating a connection from the start node and hovering the mouse over the process node. Our validation logic allows this and so the connection points on the process node are shown. However, when hovering the mouse over the end node, the validation logic notices that this is illegal and so the connection points stay hidden.

Now that we have set up the validation logic, we need to make a connection builder and connection relocator implementation that uses it. We can do this easily by extending the FlowDiagramConnectionBuilder and DefaultDiagramConnectionRelocator classes and overiding the appropriate methods. In the implementation of these methods, we simply make a call to our static validation logic method, and return the result as follows:

public class ValidatingConnectionBuilder : FlowDiagramConnectionBuilder
{
  public override bool CanCreateConnection(IDiagramModel diagram
                                                          IDiagramConnectionPoint fromConnectionPoint,
                                                          ConnectionDropTarget dropTarget)
  {
    return ConnectionValidationLogic.ValidateConnection(fromConnectionPoint, dropTarget);
  }
}

Providing the diagram with the validation logic.

Now all thats left to do is give our custom logic to the diagram. This is easily done by setting the appropriate diagram properties to be instances of our connection builder and relocator classes.

FlowDiagramModel diagram = new FlowDiagramModel();
diagram.DefaultConnectionBuilder = new ValidatingConnectionBuilder();
diagram.ConnectionRelocator = new ValidatingConnectionRelocator();

And thats it!

There are many connection validation scenarios that can be handled in this way. You could prevent certain types of nodes being directly connected to themselves, only allow specific types of connections to be made between certain node types, or even prevent particular diagram node instances from being connected together. If you download the latest nightly build you will find a new project in the flow diagram samples solution called ConnectionValidationSample. The sample prevent StartNodes being connected to EndNodes, DecisionNodes can only be accessed by a StartNode, and data-ProcessNodes can not connect to themselves. Use this to see how it all works and give you ideas to implement your own validation logic.

Try this out if you are in need of custom connection validation. If you are having trouble getting it to work or can’t seem to get the logic right for a certain scenario, then let us know in our forum, or put a comment on this blog post.

Leave a Reply

Data Products Visual Controls Community Store
LightSpeed ORM
NHibernate Designer
SimpleDB Tools
SharePoint Tools
WPF Elements
WPF Diagrams
Silverlight Elements
Forums
Blog
Register
Login
Subscribe to newsletter
Buy Now
My Account
Volume Discounts
Purchase Orders
Contact Us