Forbid point-to-shape connections?

Oct 11, 2012 at 12:18 PM

Can I forbid point-to-shape connections and allow only point-to-point connections?

I've searched for "point-to-shape" string in the Help System but couldn't find the answer.

Coordinator
Oct 11, 2012 at 12:28 PM

Yes.
If you don't want Point-To-Shape connections, return false for HasControlPointCapability(ControlPointId.Reference, ControlPointCapability.Connect).

Oct 12, 2012 at 10:03 AM

Thank you.

I also noticed that returning false from IsConnectionPointEnabled() method (when pointId == ControlPointId.Reference) gives the same effect. Which variant is preferrable?

Currently I am already using the IsConnectionPointEnabled() method to disable all points except 4 and 5 for a shape inherited from FlowChartShapes.PreparationSymbol shape.

Coordinator
Oct 12, 2012 at 11:06 AM

The final result should be the same although removing the capability from the control point is slightly more correct as you do not want the control point to be a connection point at all.

The difference is that your connection point actually is a valid connection point but it's disabled. Due to this fact, the control point is processed for all actions that use connection points. It is also taken into account for hit tests on connection points.
When removing the "Connect" capability by returning false from HasControlPointCapability(...), the control point is not a connection point any longer and is therefore ignored for all connection point relevant actions.

Normally, the result of IsControlPointEnabled is determined by checking whether the shape has a model object assigned. If no model object is assigned, all connection points are enabled by default. In case there is a model object assigned, IsConnectionPointEnabled checks whether the connection point is mapped to one of the model object's connection terminals and returns the result.
The idea behind is that connection points usually have meanings (plus/minus pole, input/output, etc) when the shape represents a model object that has connection terminals.

Oct 12, 2012 at 11:56 AM
KurtHolzinger wrote:

Normally, the result of IsControlPointEnabled is determined by checking whether the shape has a model object assigned. If no model object is assigned, all connection points are enabled by default. In case there is a model object assigned, IsConnectionPointEnabled checks whether the connection point is mapped to one of the model object's connection terminals and returns the result. 

The idea behind is that connection points usually have meanings (plus/minus pole, input/output, etc) when the shape represents a model object that has connection terminals.

In my other topic ("Preventing connection to a given connection point") you recommended to override the AttachGluePointToConnectionPoint() method in the passive shape to prevent certain connections. But now it seems that it is more correct to place this prevention logic into the model objects, right? Maybe I'm misunderstanding you, but I imagined the following scenario:

  • I have my custom shape PipeShape with 2 terminals: input and output.
  • I have model object PipeModel with 2 corresponding properties: Input and Output.
  • I map those terminals to those properties.
  • My prevention logic sounds like this: "Pipe allows only one incoming connection and only one outgoing connection".
  • In the IsControlPointEnabled() method I call PipeModel's method IsConnectionAllowed(...) which somehow checks if the PipeModel's property Input (or Output - depends upon what are we trying to connect) is already "busy". If yes - it returns false, and so does the IsControlPointEnabled() method.

The last check is not very clear for me - especially the parts marked red. Could you please clarify? Or maybe this scenario is not valid and I should place this check in the AttachGluePointToConnectionPoint() method?

Thank you.

Coordinator
Oct 12, 2012 at 12:33 PM

Ok, perhaps I should put less background details in my answers... ;-)

Terminals are the ModelObject's equivalent of "connection points". This has nothing to do with property mapping although the concept is similar.
To make this clearer, please perform the following steps:

  • Start the NShape Designer and open the "Model Mappings" demo project (located in C:\Users\Public\Documents\NShape\Demo Projects)
  • Right-click the "Picture" entry in the tool box on the right and select "Edit Template". The "Template Editor" dialog opens.
  • On the left side, there is a combo box "Model:". Select the "GenericModelObject" here. You will notice that 3 tabs are added at the right side: "Model", "Connection Points" and "Model Visualization". 
  • The "Model Visualization" tab is for property mapping as you already know it.
  • Select the "Connection Points" tab and you will see the shape and its connection points on the left and a list of Control Points and Terminals on the right side.
  • Select "Terminal 1" from the combo box behind control point "4" and press the Enter key. You will notice that the shape's connection point is now green (activated) because you mapped a terminal to it. Select "Terminal 2" for connection point "5" and click "OK".
  • Now place a new "picture" shape on the diagram. Deselect it and select the Polyline tool in the tool box. When you move the mouse near the picture shape, you will notice that you can only connect the Polyline to connection points "4" and "5". This is because they are mapped to the model object's terminals.

In order to use this functionality, you don't need to code a single line - it's all implemented in the base classes (see ShapeBase.IsConnectionPointEnabled).
But you need a template and you need to add TerminalMappings to the template (done by the template editor in this case) in order to use this feature.

By the way: This is a static mapping. The terminal mappings must not change after shapes are created from the template. If you open the template editor again, you will notice that the tab is read only as long as the there are shapes in the repository created from this template.

Oct 12, 2012 at 12:40 PM
KurtHolzinger wrote:

By the way: This is a static mapping. The terminal mappings must not change after shapes are created from the template. If you open the template editor again, you will notice that the tab is read only as long as the there are shapes in the repository created from this template.

Well, this means that my "connection prevention logic" has to reside in the passive shape's AttachGluePointToConnectionPoint() method - because this logic is not static (it takes into account number of existing connections which may change in time).

Thank you for such a detailed answer! I really appreciate your help.