Arrows on curves detached

Hi Walter,

In our product, the link routes are changed dynamically through the binding. If we switch to a curved relationship, it looks like below:
Is there a way to ensure the arrow will look like its coming from the line.
Can we adjust LinkPanel.Alignment and LinkPanel.Orientation somehow?
Can we bind to these properties to change them as we change to different route types?

If you manually or programmatically change the position of either node, does the link route itself correctly?

When you change the bound data in the model, do you do so within a model transaction? I’m guessing that’s not happening, so the link doesn’t get a chance to re-route.

Hi Walter,

I've inherited this problem from Mike. You were right, we weren't using transactions, so I tried wrapping the change to curved links in starttransaction/committransaction, but it had no affect.
When you manually move the "to" node, the arrowhead stays detached. The amount of offset changes as you move it around though.
Do you have any other ideas?

How big is the “test unit” node? Is it much wider than the visible icon and “test unit” TextBlock?

The other oddity is that the arrowhead is not aligned correctly with the end of the link shape. Normally if you just set the attached ToArrow property, everything just works:

<DataTemplate x:Key="LinkTemplate"> <go:LinkPanel go:Part.SelectionElementName="Path" go:Part.SelectionAdorned="True"> <!-- the link's Route is drawn as a Bezier curve --> <go:Link.Route> <go:Route Curve="Bezier" /> </go:Link.Route> <!-- a simple thin black line --> <go:LinkShape x:Name="Path" Stroke="Black" StrokeThickness="1" /> <!-- a standard arrowhead --> <Path Fill="Black" go:LinkPanel.ToArrow="Standard" /> </go:LinkPanel> </DataTemplate>
This is taken from the Beat Paths sample.

We weren’t setting the ToArrow property. So I added it to our template(see below). Unfortunately, that did not fix it. The test unit node is bigger than the icon. It is 20x20.

<DataTemplate x:Key="linkTemplate">
<go:LinkPanel go:Part.SelectionElementName="Path" go:Part.SelectionAdorned="True" go:Part.Selectable="True" go:Part.LayerName="Background" Opacity="{Binding Data.Opacity}"
go:Part.Reshapable="True"> <go:Link.Route> <go:Route Routing="{Binding Data.Routing}" Curve="{Binding Data.Curve}" Corner="10"/> </go:Link.Route> <Path Fill="Black" go:LinkPanel.ToArrow="Standard" /> <Grid DataContext="{Binding Data}"> <telerik:RadContextMenu.ContextMenu> <rivet:ContextMenu /> </telerik:RadContextMenu.ContextMenu> <go:LinkShape StrokeDashArray="{Binding FormatSettings.LineStyle}" go:LinkPanel.IsLinkShape="True" x:Name="Path" StrokeThickness="{Binding FormatSettings.LineThickness}" > <go:LinkShape.Stroke> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop x:Name="Stop1" Color="{Binding FormatSettings.LineColor}" Offset="0" /> <GradientStop x:Name="Stop2" Color="{Binding FormatSettings.LineColor}" Offset="1" /> </LinearGradientBrush> </go:LinkShape.Stroke> </go:LinkShape> </Grid> <Polyline StrokeThickness="{Binding Data.LineThickness}" Points="8 4 0 8 2 4 0 0" go:LinkPanel.Index="-1" go:LinkPanel.Alignment="Center" go:LinkPanel.Orientation="Along" Visibility="{Binding Data.Direction, ConverterParameter=From, Converter={StaticResource arrowheadToVisibilityConverter}}"> <Polyline.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop x:Name="Stop1Left" Color="{Binding Data.ConnectedColor}" Offset="0" /> <GradientStop x:Name="Stop2Left" Color="{Binding Data.ConnectedColor}" Offset="1" /> </LinearGradientBrush> </Polyline.Fill> </Polyline> <Polyline StrokeThickness="{Binding Data.LineThickness}" Points="0 4 8 0 6 4 8 8" go:LinkPanel.Alignment="Center" go:LinkPanel.Index="0" go:LinkPanel.Orientation="Along" Visibility="{Binding Data.Direction, ConverterParameter=To, Converter={StaticResource arrowheadToVisibilityConverter}}"> <Polyline.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop x:Name="Stop1Right" Color="{Binding Data.ConnectedColor}" Offset="0" /> <GradientStop x:Name="Stop2Right" Color="{Binding Data.ConnectedColor}" Offset="1" /> </LinearGradientBrush> </Polyline.Fill> </Polyline> <go:NodePanel Sizing="Auto" go:LinkPanel.Orientation="None" go:LinkPanel.Offset="10 NaN"> <ContentControl ContentTemplate="{StaticResource LinkLabelTemplate}" Content="{Binding Data.Self}"/> </go:NodePanel> </go:LinkPanel> </DataTemplate>
Here is our node template:
<DataTemplate x:Key="nodeTemplate"> <go:NodePanel x:Name="nodePanel" go:Node.Location="{Binding Data.Location, Mode=TwoWay}" Opacity="{Binding Data.Opacity}" MouseLeftButtonDown="OnHandleDoubleClick" RenderTransformOrigin="0.5,0.5"> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseEnter"> <mvvm:EventToCommand Command="{Binding DataContext.ScaleToZoomFactorCommand, ElementName=myDiagram}" CommandParameter="{Binding ElementName=nodePanel}" /> </i:EventTrigger> <i:EventTrigger EventName="MouseLeave"> <mvvm:EventToCommand Command="{Binding DataContext.ScaleToZoomedSizeCommand, ElementName=myDiagram}" CommandParameter="{Binding ElementName=nodePanel}" /> </i:EventTrigger> </i:Interaction.Triggers> <go:NodePanel.RenderTransform> <ScaleTransform x:Name="panelTransform" ScaleX="1.0" ScaleY="1.0" /> </go:NodePanel.RenderTransform> <i:Interaction.Behaviors> <Behaviors:ShowHideBehavior /> </i:Interaction.Behaviors> <Grid DataContext="{Binding Data}"> <telerik:RadContextMenu.ContextMenu> <rivet:ContextMenu /> </telerik:RadContextMenu.ContextMenu> <rivet:EntityControl ShowArrow="False" x:Name="entityCard" DataContext="{Binding Self, Converter={StaticResource iobjectToEntityControlViewModelConverter}}" HorizontalAlignment="Left" MaxWidth="250" go:Node.LinkableFrom="True" go:Node.LinkableTo="True" go:Part.Movable="True"/> </Grid> <Image Opacity="0" Cursor="Hand" HorizontalAlignment="Center" VerticalAlignment="Center" Source="{StaticResource CrossHairImage}" Width="{Binding Data.Self, Converter={StaticResource sizeToEntityCardConverter}}" Stretch="Uniform"/> <Button Width="20" Height="20" Content="+" Visibility="{Binding Data.ShowRelationshipIndicator, Converter={StaticResource boolToVisibilityConverter}}" Style="{StaticResource ExpansionButtonStyle}"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <mvvm:EventToCommand Command="{Binding Data.ExpandRelationshipsCommand}" CommandParameter="{Binding Data.Self}" /> </i:EventTrigger> </i:Interaction.Triggers> <ToolTipService.ToolTip> <TextBlock Text="{Binding Data.NumberOfRelationships}" /> </ToolTipService.ToolTip> <Button.RenderTransform> <TranslateTransform X="-22" Y="-35"/> </Button.RenderTransform> </Button> </go:NodePanel> </DataTemplate>

LinkPanel has several attached properties that, like other panel attached properties, should be set on the immediate child elements of the panel. That’s not the case here. Furthermore the LinkShape must be an immediate child of the LinkPanel, not inside a Grid. So you need to remove the Grid and move the context menu – I suggest to the LinkPanel.

The NodePanel inside the link template seems superfluous. Just set those LinkPanel attached properties directly on the ContentControl.

Regarding the node DataTemplate, it doesn’t make sense for the main object of the NodePanel to be a Grid containing a context menu. I suspect the main object used to be either the Image or the EntityControl. Remove the Grid and move the context menu elsewhere, such as on the whole NodePanel.

Part or Node or Link attached properties go on the root element of the DataTemplate. (There are some exceptions, such as port-related attached properties.) So the go:Part.Movable=“True” should not be there. It’s unnecessary anyway, because that’s the default value.

And the two port-related properties, go:Node.LinkableFrom and LinkableTo are useless there because you haven’t declared that element to be a port by setting go:Node.PortId to a string. (Well, maybe you do so programmatically, but that’s unlikely.)

Anyway, I’m guessing that the problem is that links are connecting to the edge of your nodes, but it doesn’t look that way because the EntityControl is not visible for some reason and that it’s a lot bigger than the Image.