Sorry if I’m missing something, but I don’t see any assignment or binding of go:Node.PortId, which is required to declare some FrameworkElement as a “port” in a node.
That is set in the templates in a post above, but here it is again:
<div style="font-family: 'Courier New', Courier, mono; white-space: pre; : rgb248, 248, 252;"><DataTemplate x:Key="DynamicPortItemDiagramTemplate"><div style="font-family: 'Courier New', Courier, mono; white-space: pre; : rgb248, 248, 252;"> <Rectangle Width="7" Height="7" Cursor="Hand" Fill="Transparent"<div style="font-family: 'Courier New', Courier, mono; white-space: pre; : rgb248, 248, 252;"> go:Node.PortId="{Binding Path=ID, Mode=OneWay}"<div style="font-family: 'Courier New', Courier, mono; white-space: pre; : rgb248, 248, 252;"> go:Node.LinkableFrom="True" go:Node.LinkableTo="True"<div style="font-family: 'Courier New', Courier, mono; white-space: pre; : rgb248, 248, 252;"> go:Node.FromSpot="{Binding Path=ToFromSpot, Mode=OneWay}" go:Node.ToSpot="{Binding Path=ToFromSpot, Mode=OneWay}"<div style="font-family: 'Courier New', Courier, mono; white-space: pre; : rgb248, 248, 252;"> StrokeThickness="{Binding ElementName=PortValues, Path=StrokeThickness}"<div style="font-family: 'Courier New', Courier, mono; white-space: pre; : rgb248, 248, 252;"> Stroke="{Binding ElementName=PortValues, Path=Stroke}" /><div style="font-family: 'Courier New', Courier, mono; white-space: pre; : rgb248, 248, 252;"> </DataTemplate>
And I did test in GetLinkDirection that each FrameworkElement in node.Ports has the expected PortId.
GetLinkDirection is called with a Node and port FrameworkElement for each end of the link.
However, the Node and FrameworkElement might not be the Link.FromNode/FromPort or ToNode/ToPort for various reasons. The most common case occurs when the port is not visible. Might your port be inside an invisible panel?
My guess is that this is related to the way the ItemsControl control works. I know the tree looks something like: ItemsControl -> ItemsPanel -> ContentPresenter -> Item. In this case, the Item is the Rectangle being used as the port. I know the ItemsPanel is visible, but the ContentPresenter may not be.
I’m not sure if this matters with the way the base code works, but for the ports in the ItemsControl their Parent is set to null.
Node.FindPort uses VisualTreeHelper to walk the visual tree. You are certain that the go:Node.PortId is unique within each Node? (Sorry if I have asked that already.) I was going to suggest calling Node.FindPort to make sure you are getting the FrameworkElement that you expected, but that might be misleading.
FrameworkElement.Parent is the parent element in the logical tree, so it is expected to be null for a templated element.
Yes they are all unique… So you are suggesting that we use Node.FindPort to find the correct FrameworkElement for the port and just use that instead of the one being passed to GetLinkDirection?
Oh, no – the arguments passed to the Route methods such as GetLinkDirection really are the ones that they should be using.
I still don’t see why you are getting passed as the port the Viewbox named “V1”. There is at least a Grid and another Viewbox between the ItemsControl and the “V1” Viewbox. And there’s another panel containing that Viewbox. And the use of Rectangles as ports in an ItemsControl can work, as shown in the Dynamic Ports sample. If you don’t use any Viewboxes, does that help any?
If I get rid of the viewboxes then GetLinkDirection does get passed the correct FrameworkElement… but we do need them as they have solved the other issues we’ve had with positioning of the ports.
I can certainly see how using Viewboxes would help with the sizing of the elements, but not with the positioning.
We’ll need to look into this further.