title: WPF/Silverlight Bind Canvas to Collection of View Model Elements
body: <p>Is it possible to use a DataTemplate to render a collection of points as a bunch of lines (with data binding and drag and drop)?</p>
  
  <p>Here are the details:</p>
  
  <p>I have multiple objects in my view model. These objects ultimately have locations on a canvas specified in absolute pixel coordinates. I need to be able to drag and drop these items around on the canvas and update their coordinates. Some objects are represented by a point, others are a collection of line segments. I'm using MVVM (Jounce). Should my view model expose a <code>ObservableCollection&lt;Shape&gt;</code> that somehow binds the coordinates? That feels wrong. Or is there a way I can use DataTemplates here to draw lines with points on the end of each line segment given a collection of line segments? Here is an example ViewModel:</p>
  
  <pre><code>using System.Collections.Generic;
  using System.Collections.ObjectModel;
  using Jounce.Core.ViewModel;
  
  namespace CanvasBindTest.ViewModels
  {
      /// &lt;summary&gt;
      /// Sample view model showing design-time resolution of data
      /// &lt;/summary&gt;
      [ExportAsViewModel(typeof(MainViewModel))]
      public class MainViewModel : BaseViewModel
      {
          public MainViewModel()
          {
              var start = new PointView { X = 0, Y = 0 };
              var middle = new PointView { X = 1132 / 2, Y = 747 / 2 };
              var end = new PointView() { X = 1132, Y = 747 };
              var lineView = new LineView(new[] { start, middle, end });
              Lines = new LinesView(new[] { lineView });
          }
  
          public LinesView Lines { get; private set; }
      }
  
      public class LinesView : BaseViewModel
      {
          public ObservableCollection&lt;LineView&gt; Lines { get; private set; }
  
          public LinesView(IEnumerable&lt;LineView&gt; lines)
          {
              Lines = new ObservableCollection&lt;LineView&gt;(lines);
          }
      }
  
      public class LineView : BaseViewModel
      {
          public ObservableCollection&lt;PointView&gt; Points { get; private set; }
  
          public LineView(IEnumerable&lt;PointView&gt; points)
          {
              Points = new ObservableCollection&lt;PointView&gt;(points);
          }
      }
  
      public class PointView : BaseViewModel
      {
          private int x, y;
  
          public int X
          {
              get { return x; }
              set { x = value; RaisePropertyChanged(() =&gt; X); }
          }
  
          public int Y { 
              get { return y; }
              set { y = value; RaisePropertyChanged(() =&gt; Y); }
          }
      }
  }
  </code></pre>
  
  <p>Here is the View, which is a canvas wrapped in a ItemsControl with a background image. The view model coordinates are relative to the background image's unscaled size:</p>
  
  <pre><code>&lt;UserControl x:Class="CanvasBindTest.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:viewModels="clr-namespace:CanvasBindTest.ViewModels" 
      mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"&gt;
  
      &lt;UserControl.Resources&gt;
          &lt;DataTemplate x:Key="SkylineTemplate" DataType="viewModels:LineView"&gt;
              &lt;ItemsControl ItemsSource="{Binding Points}"&gt;
                  &lt;ItemsControl.ItemsPanel&gt;
                      &lt;ItemsPanelTemplate&gt;
                          &lt;!--I have a collection of points here, how can I draw all the lines I need and keep the end-points of each line editable?--&gt;
                      &lt;/ItemsPanelTemplate&gt;
                  &lt;/ItemsControl.ItemsPanel&gt;
              &lt;/ItemsControl&gt;
          &lt;/DataTemplate&gt;
      &lt;/UserControl.Resources&gt;
  
      &lt;Grid d:DataContext="{d:DesignInstance viewModels:MainViewModel, IsDesignTimeCreatable=True}"&gt;
          &lt;ScrollViewer x:Name="Scroll"&gt;
              &lt;ItemsControl ItemsSource="{Binding Lines}"&gt;
                  &lt;ItemsControl.ItemsPanel&gt;
                      &lt;ItemsPanelTemplate&gt;
                          &lt;Canvas&gt;
                              &lt;Canvas.Background&gt;
                                  &lt;ImageBrush Stretch="Uniform" ImageSource="Properties/dv629047.jpg"/&gt;
                              &lt;/Canvas.Background&gt;
                          &lt;/Canvas&gt;
                      &lt;/ItemsPanelTemplate&gt;
                  &lt;/ItemsControl.ItemsPanel&gt;
              &lt;/ItemsControl&gt;
          &lt;/ScrollViewer&gt;
      &lt;/Grid&gt;
  &lt;/UserControl&gt;
  </code></pre>