Link to Port connection display problem

Hello,

I’m using GoXam Silverlight (Version 1.0.1.3)

When i load a diagram, my link aren’t correctly connected to my ports nodes (visually), but are all connected to the top left edge of my node (See screenshot 1 below).
And if i drag a node with the mouse, then the links connected to that node are rendered correctly and visually connected to the right ports. (See scrennshot 2 below)

It’s an odd problem and i don’t really understand where does it come from.
In my diagram model, everything seems to be all right considering nodes and links To, From, ToPort, FromPort properties.

Maybe, it come from my node DataTemplate (See NodeDataTemplate below). i should be missing a property or something. Can you help me please ?

Screenshot 1 :

Screenshot 2 :

Node DataTemplate :

<!-- Diagram : StepNode -->
        <DataTemplate x:Key="DiagramStepNode" >
            <Border Grid.Row="0"
                    Grid.Column="0"
                    Grid.RowSpan="3"
                    Grid.ColumnSpan="3"
                    BorderBrush="LightGray"
                    Background="White"
                    BorderThickness="1"
                    CornerRadius="10"
                    Padding="5"
                    go:Node.Location="{Binding Path=Node.Data.Location, Mode=TwoWay}"
                    go:Node.SelectionElementName="SelectionShape"
                    go:Node.SelectionAdorned="True"
                    x:Name="SelectionShape"
                    MouseEnter="Node_MouseEnter"
                    MouseLeave="Node_MouseLeave">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <!-- Forme et texte du noeud -->
                    <go:SpotPanel Grid.Row="1"
                                  Grid.Column="0"
                                  Style="{StaticResource SpotPanelStyle}">
                        <!-- Noeud -->
                        <go:NodePanel Sizing="Auto">
                            <!-- Forme du noeud-->
                            <Path 
                                  Stroke="Black"
                                  StrokeThickness="2"
                                  Fill="{Binding Path=Data.Node.Color, Converter={StaticResource ColorStringToLinearGradientBrushConverter}}"
                                  go:NodePanel.Figure="{Binding Path=Data.Node.Shape, Converter={StaticResource IntegerToNodeFigureConverter}}" />
                            <!-- Texte du noeud -->
                            <TextBlock Style="{StaticResource NodeTextStyle}"
                                           Text="{Binding Path=Data.Node.Text, Mode=TwoWay}"
                                           go:Part.TextEditable="True" />
                            <!-- ToolTip : Texte du noeud -->
                            <ToolTipService.ToolTip>
                                <ToolTip>
                                    <ToolTip.Content>
                                        <TextBlock Style="{StaticResource TextStyle}"
                                                   Text="{Binding Path=Data.Node.Text}" />
                                    </ToolTip.Content>
                                </ToolTip>
                            </ToolTipService.ToolTip>
                        </go:NodePanel>
                        <!-- 8 Ports -->
                        <!-- Port Haut gauche (4) -->
                        <Ellipse Style="{StaticResource PortStyle}"
                                 Visibility="{Binding Path=Data.ShowPorts, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}"
                                 go:Node.PortId="4"
                                 go:Node.FromSpot="TopLeft"
                                 go:SpotPanel.Spot="TopLeft"
                                 go:SpotPanel.Alignment="TopLeft" />
                        <!-- Port Haut droite (5) -->
                        <Ellipse Style="{StaticResource PortStyle}"
                                 Visibility="{Binding Path=Data.ShowPorts, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}"
                                 go:Node.PortId="5"
                                 go:Node.FromSpot="TopRight"
                                 go:SpotPanel.Spot="TopRight"
                                 go:SpotPanel.Alignment="TopRight" />
                        <!-- Port Bas gauche (6) -->
                        <Ellipse Style="{StaticResource PortStyle}"
                                 Visibility="{Binding Path=Data.ShowPorts, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}"
                                 go:Node.PortId="6"
                                 go:Node.FromSpot="BottomLeft"
                                 go:SpotPanel.Spot="BottomLeft"
                                 go:SpotPanel.Alignment="BottomLeft" />
                        <!-- Port Bas droite (7) -->
                        <Ellipse Style="{StaticResource PortStyle}"
                                 Visibility="{Binding Path=Data.ShowPorts, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}"
                                 go:Node.PortId="7"
                                 go:Node.FromSpot="BottomRight"
                                 go:SpotPanel.Spot="BottomRight"
                                 go:SpotPanel.Alignment="BottomRight" />
                        <!-- Port Bas milieu (0) -->
                        <Ellipse Style="{StaticResource PortStyle}"
                                 Visibility="{Binding Path=Data.ShowPorts, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}"
                                 go:Node.PortId="0"
                                 go:Node.FromSpot="MiddleBottom"
                                 go:SpotPanel.Spot="MiddleBottom"
                                 go:SpotPanel.Alignment="MiddleBottom" />
                        <!-- Port Haut milieu (1) -->
                        <Ellipse Style="{StaticResource PortStyle}"
                                 Visibility="{Binding Path=Data.ShowPorts, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}"
                                 go:Node.PortId="1"
                                 go:Node.ToSpot="MiddleTop"
                                 go:SpotPanel.Spot="MiddleTop"
                                 go:SpotPanel.Alignment="MiddleTop" />
                        <!-- Port Gauche milieu (2) -->
                        <Ellipse Style="{StaticResource PortStyle}"
                                 Visibility="{Binding Path=Data.ShowPorts, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}"
                                 go:Node.PortId="2"
                                 go:Node.FromSpot="MiddleLeft"
                                 go:Node.ToSpot="MiddleLeft"
                                 go:SpotPanel.Spot="MiddleLeft"
                                 go:SpotPanel.Alignment="MiddleLeft" />
                        <!-- Port Droite milieu (3) -->
                        <Ellipse Style="{StaticResource PortStyle}"
                                 Visibility="{Binding Path=Data.ShowPorts, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}"
                                 go:Node.PortId="3"
                                 go:Node.FromSpot="MiddleRight"
                                 go:Node.ToSpot="MiddleRight"
                                 go:SpotPanel.Spot="MiddleRight"
                                 go:SpotPanel.Alignment="MiddleRight" />
                    </go:SpotPanel>
                    <!-- Icone affectations -->
                    <Rectangle Grid.Row="0"
                               Grid.Column="1"
                               Style="{StaticResource StepIconSizeStyle}"
                               Fill="{Binding Path=Data, Converter={StaticResource IconBrushConverter}, ConverterParameter=customers_128.png}"
                               Effect="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToDisableEffectConverter}, ConverterParameter=AFF}"
                               Cursor="Hand">
                        <!-- Tooltip Icone affectations -->
                        <ToolTipService.ToolTip>
                            <ToolTip>
                                <ToolTip.Content>
                                    <Grid>
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                        </Grid.RowDefinitions>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto" />
                                        </Grid.ColumnDefinitions>
                                        <TextBlock Grid.Row="0"
                                                   Grid.Column="0"
                                                   Style="{StaticResource BoldTextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource LibelleConverter}, ConverterParameter=154086}" />
                                        <TextBlock Grid.Row="1"
                                                   Grid.Column="0"
                                                   Style="{StaticResource TextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToStringConverter}, ConverterParameter=AFF}" />
                                    </Grid>
                                </ToolTip.Content>
                            </ToolTip>
                        </ToolTipService.ToolTip>
                    </Rectangle>
                    <!-- Popup affectations -->
                    <Border Grid.Row="0"
                                Grid.Column="2"
                                Style="{StaticResource PopUpStyle}"
                                Visibility="{Binding Path=Node.Data.ShowAffectation, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <TextBlock Grid.Row="0"
                                       Grid.Column="0"
                                       Style="{StaticResource BoldTextStyle}"
                                       Text="{Binding Path=Node.Data, Converter={StaticResource LibelleConverter}, ConverterParameter=154086}" />
                            <TextBlock Grid.Row="1"
                                       Grid.Column="0"
                                       Style="{StaticResource TextStyle}"
                                       Text="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToStringConverter}, ConverterParameter=AFF}" />
                        </Grid>
                    </Border>
                    <!-- Icone notifications -->
                    <Rectangle Grid.Row="2"
                               Grid.Column="1"
                               Style="{StaticResource StepIconSizeStyle}"
                               Fill="{Binding Path=Data, Converter={StaticResource IconBrushConverter}, ConverterParameter=enveloppe_email_128.png}"
                               Effect="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToDisableEffectConverter}, ConverterParameter=DIFF}"
                               Cursor="Hand">
                        <!-- Tooltip de l'icone notfications -->
                        <ToolTipService.ToolTip>
                            <ToolTip>
                                <ToolTip.Content>
                                    <Grid>
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                        </Grid.RowDefinitions>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto" />
                                        </Grid.ColumnDefinitions>
                                        <!-- Autres notifications -->
                                        <TextBlock Grid.Row="0"
                                                   Grid.Column="0"
                                                   Style="{StaticResource BoldTextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource LibelleConverter}, ConverterParameter=154094}" />
                                        <TextBlock Grid.Row="1"
                                                   Grid.Column="0"
                                                   Style="{StaticResource TextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToStringConverter}, ConverterParameter=DIFF}" />
                                        <!-- Seperateur -->
                                        <TextBlock Grid.Row="2"
                                                   Grid.Column="0"
                                                   Style="{StaticResource BoldTextStyle}"
                                                   Text="________________________" />
                                        <!-- Lorsque l'étape est réalisable -->
                                        <TextBlock Grid.Row="3"
                                                   Grid.Column="0"
                                                   Style="{StaticResource BoldTextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource LibelleConverter}, ConverterParameter=154088}" />
                                        <TextBlock Grid.Row="4"
                                                   Grid.Column="0"
                                                   Style="{StaticResource TextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToStringConverter}, ConverterParameter=MAIL_REALISABLE}" />
                                        <!-- Lors de la réalisation de l'étape -->
                                        <TextBlock Grid.Row="5"
                                                   Grid.Column="0"
                                                   Style="{StaticResource BoldTextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource LibelleConverter}, ConverterParameter=154089}" />
                                        <TextBlock Grid.Row="6"
                                                   Grid.Column="0"
                                                   Style="{StaticResource TextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToStringConverter}, ConverterParameter=MAIL_REALISATION}" />
                                        <!-- Lors d'un classement sans suite -->
                                        <TextBlock Grid.Row="7"
                                                   Grid.Column="0"
                                                   Style="{StaticResource BoldTextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource LibelleConverter}, ConverterParameter=154090}" />
                                        <TextBlock Grid.Row="8"
                                                   Grid.Column="0"
                                                   Style="{StaticResource TextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToStringConverter}, ConverterParameter=MAIL_CLASS}" />
                                        <!-- Lors d'un changement de workflow -->
                                        <TextBlock Grid.Row="9"
                                                   Grid.Column="0"
                                                   Style="{StaticResource BoldTextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource LibelleConverter}, ConverterParameter=154091}" />
                                        <TextBlock Grid.Row="10"
                                                   Grid.Column="0"
                                                   Style="{StaticResource TextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToStringConverter}, ConverterParameter=MAIL_CHG_WF}" />
                                        <!-- Lors d'un retour sur une étape -->
                                        <TextBlock Grid.Row="11"
                                                   Grid.Column="0"
                                                   Style="{StaticResource BoldTextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource LibelleConverter}, ConverterParameter=154092}" />
                                        <TextBlock Grid.Row="12"
                                                   Grid.Column="0"
                                                   Style="{StaticResource TextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToStringConverter}, ConverterParameter=MAIL_RETOUR}" />
                                        <!-- Tiers -->
                                        <TextBlock Grid.Row="13"
                                                   Grid.Column="0"
                                                   Style="{StaticResource BoldTextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource LibelleConverter}, ConverterParameter=154093}" 
                                                   Visibility="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToVisibilityConverter}, ConverterParameter=MAIL_TIERS}" />
                                        <TextBlock Grid.Row="14"
                                                   Grid.Column="0"
                                                   Style="{StaticResource TextStyle}"
                                                   Text="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToStringConverter}, ConverterParameter=MAIL_TIERS}"
                                                   Visibility="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToVisibilityConverter}, ConverterParameter=MAIL_TIERS}" />
                                    </Grid>
                                </ToolTip.Content>
                            </ToolTip>
                        </ToolTipService.ToolTip>
                    </Rectangle>
                    <!-- Popup notifications -->
                    <Border Grid.Row="2"
                            Grid.Column="2"
                            Style="{StaticResource PopUpStyle}"
                            Visibility="{Binding Path=Node.Data.ShowNotification, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <!-- Autres notifications -->
                            <TextBlock Grid.Row="0"
                                       Grid.Column="0"
                                       Style="{StaticResource BoldTextStyle}"
                                       Text="{Binding Path=Node.Data, Converter={StaticResource LibelleConverter}, ConverterParameter=154094}" />
                            <TextBlock Grid.Row="1"
                                       Grid.Column="0"
                                       Style="{StaticResource TextStyle}"
                                       Text="{Binding Path=Node.Data, Converter={StaticResource AffectationNotificationListToStringConverter}, ConverterParameter=DIFF}" />
                        </Grid>
                    </Border>
                </Grid>
            </Border>
        </DataTemplate>

No, I suspect that’s an example of an initialization bug in Silverlight that I believe we have fixed in version 1.1. It depends on exactly what state the Diagram is in at the time the nodes and links are created, both the model data and the Diagram Parts.

So if you could try upgrading to version 1.1, you can see if the problem goes away. Since I assume you don’t want to upgrade to Visual Studio 2010, install the kit for VS2008.

I just tried to use the 1.1 dll and the problem is still the same.

Does the property Node.locationSpot has something to do with ports connections rendering ? At the moment, in my data template, it’s value is “Center” and setted by the “Style” property of the SpotPanel.

Is it a problem that my dataTemplate root visual element is a grid and not directly a SpotPanel or NodePanel ?

No, those two issues should not matter. There must be yet another combination of initialization circumstances causing this problem in Silverlight.

How and when do the Diagram and the model get created?

As a work-around, you can implement a Diagram.InitialLayoutCompleted event handler:

myDiagram.InitialLayoutCompleted += (s, e) => {
foreach (Node n in myDiagram.Nodes) n.InvalidateRelationships();
};

The diagram is created when my xaml page loads.

Then i call my web service to retrieve data. When i received my web service reply, i built the model with the data i just received. And finally, i set the built model to the diagram.

I have also tried to loadup the model directly from an xml string stored in the isolated storage (without the web service call), but the result is the same. Links are not correctly linked until i start moving the different nodes with my mouse.

And the workaround doesn’t change anything.

I’m very surprised about the work-around not changing anything.

When the InitialLayoutCompleted event handler is called, how many Diagram.Nodes are there?

At the first pass : 0 node
At the second pass : 8 nodes

When i have done the test i was using a 8 nodes diagram. Not the one with 3 nodes that you can see in the screenshot above.

All right, after a day trying almost everything possible i finally found what was wrong !

This was wrong (or a bad idea…):

[code]

                        <Ellipse Style="{StaticResource PortStyle}"
                                 Visibility="{Binding Path=Data.ShowPorts, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}"
                                 go:Node.PortId="4"
                                 go:Node.FromSpot="TopLeft"
                                 go:SpotPanel.Spot="TopLeft"
                                 go:SpotPanel.Alignment="TopLeft" />
[/code]

Explanation :
Because the Data.showPorts value was set to False in the my DataNode constructor, then the ellipse representing ports were not drawn by Silverlight, then it wasn’t possible to connect the link to an invisible object.

…my mistake.

Thanks for your help anyway !

I’m glad you found the problem. I’ve spent time trying to reproduce the problem using your template, but was unable to find any problems because I had simplified things not to use any Styles or Converters, because I didn’t have any of your definitions.

I did notice, though, that you often use data bindings like:
{Binding Path=Node.Data… }

Although that may work, there could be initialization problems with that because the Node might not be fully initialized at the time of the binding.

Instead you should do:
{Binding Path=Data… }

This will be more efficient, as well as more reliable because of potential initialization issues.

Generally one only data-binds to:
{Binding Path=Node… }
or
{Binding Path=Link… }
when trying to bind to transient information about the Parts, not about the Data.

Actually, I take it back: Path=Node.Data… should work reliably.

It’s bindings such as Path=Node.LinksConnected or Path=Node.NodesInto that are properties whose value may vary as Nodes and Links are loaded into the Diagram. But they are not dependency properties and their values are not ObservableCollections, so any bindings depending on those collection values might not be updated.

Still, it’s inefficient when you can use bind to Path=Data… directly.