Link validation

In many diagrams there are semantic restrictions on which links could be considered “valid”.

A good user interface will try to prevent the user from drawing invalid links. This is much friendlier than permitting “bad” links and then trying to point out the errors much later.

There are two linking tools: LinkingTool for drawing new links and RelinkingTool for reconnecting existing links. There are several built-in properties and methods that will help you constrain the links that the user may create using these tools.

No links can be drawn by the user unless the Diagram has a LinkingTool and there are nodes with valid ports from which the user can draw new links. So you can easily prevent new links from being drawn by:

  • not having any elements in your node DataTemplate acting as valid ports, or
  • not setting DiagramModel.Modifiable to true, or
  • making the Diagram.IsReadOnly or setting Diagram.AllowLink false, or
  • removing the LinkingTool by setting Diagram.LinkingTool to null in either XAML or code
The first condition holds true by default. If you want users to draw new links interactively, say from node A to node B, you have to make sure that node A has at least one FrameworkElement with the Node.LinkableFrom attached property set to true, and that node B has at least one FrameworkElement with the Node.LinkableTo attached property set to true.

No links can be reconnected by users unless the Diagram has a RelinkingTool and there are links with a “Relinkable…” property set to true and there are valid nodes to connect to. You can prevent users from reconnecting existing links by:

  • not setting the Route.RelinkableFrom and Route.RelinkableTo properties in your link DataTemplate to true, or
  • not setting DiagramModel.Modifiable to true, or
  • making the Diagram.IsReadOnly or setting Diagram.AllowRelink false, or
  • removing the RelinkingTool by setting Diagram.RelinkingTool to null in either XAML or code
But often one desires constraints on the permitted links in a diagram. There are some predefined properties that are convenient for declaring certain cases, and there are some methods that you can override for the general situation.

The Node.LinkableSelfNode attached property can be set to true on FrameworkElements acting as ports in order to permit both ends of a link to be the same node. (By default reflexive links are not allowed.)

The Node.LinkableDuplicates attached
property can be set to true on FrameworkElements acting as ports in
order to allow
more than one link connecting the same two ports in the same direction. (By default multiple links are not allowed.)

The Node.LinkableMaximum attached property can be set on FrameworkElements acting as ports to limit how many links can be connected to that port in either direction. (By default there is no limit.)

There is also the ValidCycle property on GraphModel and GraphLinksModel that describes what kinds of graphs are allowed. (By default all kinds of graphs are permitted.)

Finally, for the most general case, where there are application-specific reasons for allowing some links and disallowing others, you can override the IsValidLink method in both linking tools.

For example, say that you want to change the behavior of the Flow Chart sample to disallow the user from specifying links that go directly from “Start” nodes to “End” nodes. You can achieve this by adding the following override of IsValidLink to both of the custom linking tools that the Flow Chart sample defines:

public override bool IsValidLink(Node fromnode, FrameworkElement fromport, Node tonode, FrameworkElement toport) { if (!base.IsValidLink(fromnode, fromport, tonode, toport)) return false; // don't allow a link directly from Start to End MyNodeData fromnodedata = fromnode.Data as MyNodeData; MyNodeData tonodedata = tonode.Data as MyNodeData; if (fromnodedata != null && tonodedata != null && fromnodedata.Category == "Start" && tonodedata.Category == "End") return false; return true; }
Of course this is just a simple example. You can implement arbitrarily complex predicates that examine your application data.