title: Draw lines between connected nodes
body: <p><strong>Overview</strong>: I have a XAML Canvas control onto which I have placed several Line controls. The lines appear where they should not, and my conclusion is that the bounding boxes of said lines are misbehaving. I do not access or alter these bounding boxes (as far as I know).</p>
  
  <p><strong>Project details</strong>: I'm using WPF, XAML, C# and the MVVM pattern, all within Visual Studio 2010.</p>
  
  <p><strong>More detailed explanation</strong>: My project is to create a canvas and have items on that canvas that can be dragged around by the user. Lines are drawn between one item and another, to show a visual link.</p>
  
  <p>To visualise, you can see an image here: </p>
  
  <p><a href="https://i.stack.imgur.com/sTtSU.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/sTtSU.jpg" alt="enter image description here"></a></p>
  
  <p>There are five items and in the code the N1 item should be linked by lines to the N3, N4 and N5 items. The N1 to N3 line seems to be fine, but the other two are offset. If you were to move them up, they would link the items together nicely. </p>
  
  <p>The first thing you might consider is the co-ordinates of the lines within the Canvas, and I have done this. </p>
  
  <p>Please view this image:</p>
  
  <p><a href="https://i.stack.imgur.com/kIIRB.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/kIIRB.jpg" alt="enter image description here"></a></p>
  
  <p>I added a TextBlock to the XAML within the same region as the Line and bound its Text to the StartingPoint of the Line. It might be difficult to see here if the image is small, but I can tell you that the StartingPont is the same for both lines here. And yet, clearly we can see that the lines are not in the same place.</p>
  
  <p>I also thought that this could be a problem of alignment. I do not set any alignments within my project so I thought maybe this was the problem. I changed my lines to have different alignments (horizontal and vertical) as well as the items themselves, and I observed no difference.</p>
  
  <p><strong>Project in more detail:</strong></p>
  
  <p>First is the resource for the item itself. I don't imagine it makes a difference, but since I am all out of ideas, I can't discount that the problem might be somewhere unseen:</p>
  
  <pre><code>&lt;ResourceDictionary&gt;
          &lt;ControlTemplate x:Key="NodeTemplate"&gt;
              &lt;Border BorderThickness="2" BorderBrush="LightBlue" Margin="2" CornerRadius="5,5,5,5"&gt;
              &lt;StackPanel&gt;
                  &lt;TextBlock Text="Test" Background="AntiqueWhite"/&gt;
                  &lt;TextBlock Text="{Binding Path=NodeText}" Background="Aqua"/&gt;
                  &lt;/StackPanel&gt;
                  &lt;/Border&gt;
          &lt;/ControlTemplate&gt;
      &lt;/ResourceDictionary&gt;
  </code></pre>
  
  <p>Now there is, below that, the Canvas itself with the ItemsControls within:</p>
  
  <pre><code>&lt;Canvas&gt;
  
  
      &lt;ItemsControl ItemsSource="{Binding NodeList, UpdateSourceTrigger=PropertyChanged}"&gt;
          &lt;ItemsControl.ItemsPanel&gt;
              &lt;ItemsPanelTemplate&gt;
                  &lt;Canvas/&gt;
              &lt;/ItemsPanelTemplate&gt;
          &lt;/ItemsControl.ItemsPanel&gt;
          &lt;ItemsControl.ItemTemplate&gt;
              &lt;DataTemplate&gt;
                  &lt;ItemsControl ItemsSource="{Binding LineList, UpdateSourceTrigger=PropertyChanged}"&gt;
                      &lt;ItemsControl.ItemTemplate&gt;
                          &lt;DataTemplate&gt;
  
                              &lt;StackPanel&gt;
                                  &lt;Line Stroke="Black" X1="{Binding StartPoint.X}" Y1="{Binding StartPoint.Y}" X2="{Binding EndPoint.X}" Y2="{Binding EndPoint.Y}"  /&gt;
                              &lt;!--Path Stroke="Black" Data="{Binding}" Canvas.Left="0" Canvas.Top="0" StrokeMiterLimit="1"/--&gt;
                                  &lt;TextBlock Text="{Binding StartPoint}" HorizontalAlignment="Center"/&gt;
                              &lt;/StackPanel&gt;
                          &lt;/DataTemplate&gt;
                      &lt;/ItemsControl.ItemTemplate&gt;
                  &lt;/ItemsControl&gt;
              &lt;/DataTemplate&gt;
          &lt;/ItemsControl.ItemTemplate&gt;
      &lt;/ItemsControl&gt;
  
  
      &lt;ItemsControl ItemsSource="{Binding NodeList, UpdateSourceTrigger=PropertyChanged}"&gt;
          &lt;ItemsControl.ItemsPanel&gt;
              &lt;ItemsPanelTemplate&gt;
                  &lt;Canvas/&gt;
              &lt;/ItemsPanelTemplate&gt;
          &lt;/ItemsControl.ItemsPanel&gt;
          &lt;ItemsControl.ItemContainerStyle&gt;
              &lt;Style TargetType="ContentPresenter"&gt;
                  &lt;Setter Property="Canvas.Left" Value="{Binding CanvasLeft}"/&gt;
                  &lt;Setter Property="Canvas.Top" Value="{Binding CanvasTop}"/&gt;
              &lt;/Style&gt;
          &lt;/ItemsControl.ItemContainerStyle&gt;
          &lt;ItemsControl.ItemTemplate&gt;
              &lt;DataTemplate&gt;
                  &lt;Thumb Name="myThumb" Template="{StaticResource NodeTemplate}"&gt;
                      &lt;i:Interaction.Triggers&gt;
                          &lt;i:EventTrigger EventName="DragDelta"&gt;
                              &lt;cmd:EventToCommand Command="{Binding DragDeltaCommand}" PassEventArgsToCommand="True"/&gt;
                          &lt;/i:EventTrigger&gt;
                      &lt;/i:Interaction.Triggers&gt;
                  &lt;/Thumb&gt;
              &lt;/DataTemplate&gt;
          &lt;/ItemsControl.ItemTemplate&gt;
      &lt;/ItemsControl&gt;
  &lt;/Canvas&gt;
  </code></pre>
  
  <p>I do have two sections here; two separate ItemsControls which have slightly different purposes. I assume this is okay, although assumptions may be how I ended up with this problem in the first instance.</p>
  
  <p>Now the next part is some of the code behind and, I think, the main part is the OnDragDelta; the event handler for dragging the item around the Canvas:</p>
  
  <pre><code>void OnDeltaDrag(DragDeltaEventArgs e)
      {
          CanvasLeft += e.HorizontalChange;
          CanvasTop += e.VerticalChange;
  
          UpdateLines();
      }
  </code></pre>
  
  <p>And then, of course, 'UpdateLines':</p>
  
  <pre><code>public void UpdateLines()
      {
          // Assess next nodes. Their lines will need to be changed - their start points will have to move with this node.
          for (int i = 0; i &lt; this.NextNodes.Count; i++)
          {
              this.LineList.ElementAt(i).StartPoint = new Point(this.CanvasLeft, this.CanvasTop);
          }
  
          // Assess previous nodes. If they have lines to this node, the end points of those
          // lines will need to be moved (more specifically, moved to have the same coords as this).
          foreach (NodeViewModel n in this.PreviousNodes)
          {
              for (int i = 0; i &lt; n.NextNodes.Count; i++)
              {
                  if (n.NextNodes.ElementAt(i) == this)
                  {
                      n.LineList.ElementAt(i).EndPoint = new Point(this.CanvasLeft, this.CanvasTop);
                  }
              }
          }
      }
  </code></pre>