title: WPF Path Binding to PointCollection not updating UI
body: <p>I am trying to learn MVVM style updates. Not going so swimmingly.</p>
  
  <p>I'm stuck on updating a simple rectangle that is drawn based upon a change to a Point Collection. 
  On initialization, the UI Updates, but upon a simple change to the Point Collection, the Path is not updated in the UI.</p>
  
  <p>I added a few TextBlocks to make sure the Change event is getting fired, but I am a little lost at this point. </p>
  
  <p>Any help appreciated:</p>
  
  <p>XAML:</p>
  
  <pre><code>&lt;Window
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:local="clr-namespace:ExampleGreg" x:Class="ExampleGreg.MainWindow"
          Title="MainWindow" Height="161.614" Width="324.087"&gt;
      &lt;Grid x:Name="gridUser" MouseDown="click_MouseDown" &gt;
          &lt;Canvas x:Name="MeterCanvas" Margin="14,7,30,0" Background="#FFAFAFAF" Height="35" VerticalAlignment="Top"&gt;
              &lt;Path Stroke="Black" StrokeThickness="2"&gt;
                  &lt;Path.Data&gt;
                      &lt;PathGeometry x:Name="geometry"/&gt;
                  &lt;/Path.Data&gt;
              &lt;/Path&gt;
              &lt;Path Stroke="Black" StrokeThickness="2"&gt;
                  &lt;Path.Data&gt;
                      &lt;PathGeometry x:Name="polylinePwr"&gt;
                          &lt;PathGeometry.Transform&gt;
                              &lt;ScaleTransform ScaleX="{Binding ActualWidth, ElementName=MeterCanvas}" ScaleY="{Binding ActualHeight, ElementName=MeterCanvas}" /&gt;
                          &lt;/PathGeometry.Transform&gt;
                          &lt;PathGeometry.Figures&gt;
                              &lt;PathFigure IsClosed ="True" StartPoint="{Binding Path=thePoints[0]}"&gt;
                                  &lt;PathFigure.Segments&gt;
                                      &lt;PathSegmentCollection&gt;
                                          &lt;PolyLineSegment Points="{Binding thePoints, UpdateSourceTrigger=PropertyChanged}" /&gt;
                                      &lt;/PathSegmentCollection&gt;
                                  &lt;/PathFigure.Segments&gt;
                              &lt;/PathFigure&gt;
                          &lt;/PathGeometry.Figures&gt;
                      &lt;/PathGeometry&gt;
                  &lt;/Path.Data&gt;
              &lt;/Path&gt;
          &lt;/Canvas&gt;
          &lt;Label Content="{Binding thePoints[0]}" Margin="14,58,199.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/&gt;
          &lt;Label Content="{Binding thePoints[1]}" Margin="14,88,199.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/&gt;
          &lt;Label Content="{Binding thePoints[2]}" Margin="165,58,29.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/&gt;
          &lt;Label Content="{Binding thePoints[3]}" Margin="165,93,29.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/&gt;
      &lt;/Grid&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p>MainWindow:</p>
  
  <pre><code>    public partial class MainWindow : Window
  {
      private MainViewModel mvm;
      public MainWindow()
      {
          InitializeComponent();
          mvm = new MainViewModel();
          this.DataContext = mvm;
  
      }
  
      private void click_MouseDown(object sender, MouseButtonEventArgs e)
      {
          mvm.theText = mvm.theText + ".";
          mvm.ChangePoint(.4);
      }
  }
  </code></pre>
  
  <p>ModelView:</p>
  
  <pre><code>    class MainViewModel : INotifyPropertyChanged
  {
      private string _theText = "Initial";
      private PointCollection _points = new PointCollection();
      private PolyLineSegment segment;
  
      public event PropertyChangedEventHandler PropertyChanged;
      private void OnPropertyChanged(String info)
      {
          PropertyChangedEventHandler handler = PropertyChanged;
          if (handler != null)
          {
              handler(this, new PropertyChangedEventArgs(info));
          }
      }
      public MainViewModel()
      {
          ChangePoint(0.9);
      }
  
      public string theText
      {
          get { return _theText; }
          set
          {
              if (_theText != value)
              {
                  _theText = value;
                  OnPropertyChanged("theText");
              }
          }
      }
      public PointCollection thePoints
      {
          get
          { return _points; }
      }
  
      public void ChangePoint(double x)
      {
          _points.Clear();
          AddPoint(new Point(0.2, 0.2));
          AddPoint(new Point(0.2, 0.8));
          AddPoint(new Point(x, 0.8));
          AddPoint(new Point(x, 0.2));
  
          OnPropertyChanged("thePoints");
          _theText = _theText + "!";
          OnPropertyChanged("theText");
  
  
      }
  
      public void AddPoint(Point p)
      {
          _points.Add(p);
      }
  }
  </code></pre>
  
  <p>Thanks for any suggestions (that work :) )</p>
  
  <p><strong>--EDIT PER THE ANSWER BELOW--</strong>
  I added an IValueConverter Class:</p>
  
  <pre><code>    public class PointCollectionConverter : IValueConverter
  {
      #region IValueConverter Members
  
      public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
      {
          if (value.GetType() == typeof(ObservableCollection&lt;Point&gt;) &amp;&amp; targetType == typeof(PointCollection))
          {
              var pointCollection = new PointCollection();
              foreach (var point in value as ObservableCollection&lt;Point&gt;)
                  pointCollection.Add(point);
              return pointCollection;
          }
          return null;
  
      }
  
      public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
      {
          return null; //not needed
      }
  
      #endregion
  }
  </code></pre>
  
  <p>And Changed the ModelView to use an Observable Collection ...
  Updated ModelView:</p>
  
  <pre><code>    class MainViewModel : INotifyPropertyChanged
  {
      private string _theText = "Initial";
      private ObservableCollection&lt;Point&gt; _points;
      public event PropertyChangedEventHandler PropertyChanged;
  
      private void OnPropertyChanged(String info)
      {
          PropertyChangedEventHandler handler = PropertyChanged;
          if (handler != null)
          {
              handler(this, new PropertyChangedEventArgs(info));
          }
      }
  
      public MainViewModel()
      {
          _points = new ObservableCollection&lt;Point&gt;();
          _points.Add(new Point(0.2, 0.2));
          _points.Add(new Point(0.2, 0.8));
      }
  
      public string theText
      {
          get { return _theText; }
          set
          {
              if (_theText != value)
              {
                  _theText = value;
                  OnPropertyChanged("theText");
              }
          }
      }
      public ObservableCollection&lt;Point&gt; thePoints
      {
          get
          { return _points; }
      }
  
      double xAdder = 0;
      double y = 0.0;
      public void ChangePoint(double x)
      {
          y = y + .1;
          if (y &gt; .9) { y = .1; xAdder += .1; }
          _points.Add(new Point(x+xAdder, y));
          OnPropertyChanged("thePoints");
  
          _theText = _theText + "!";
          OnPropertyChanged("theText");
  
      }
  
  }
  </code></pre>
  
  <p>And updated XAML:</p>
  
  <pre><code>&lt;Window
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="clr-namespace:ExampleGreg"  x:Class="ExampleGreg.MainWindow"
      Title="MainWindow" Height="161.614" Width="324.087"&gt;
  &lt;Window.Resources&gt;
      &lt;local:PointCollectionConverter x:Key="pointCollectionConverter"/&gt;
  &lt;/Window.Resources&gt;
  &lt;Grid x:Name="gridUser" MouseDown="click_MouseDown" &gt;
      &lt;Canvas x:Name="MeterCanvas" Margin="14,7,30,0" Background="#FFAFAFAF" Height="35" VerticalAlignment="Top"&gt;
          &lt;Path Stroke="Black" StrokeThickness="2"&gt;
              &lt;Path.Data&gt;
                  &lt;PathGeometry x:Name="geometry"/&gt;
              &lt;/Path.Data&gt;
          &lt;/Path&gt;
          &lt;Path Stroke="Black" StrokeThickness="2"&gt;
              &lt;Path.Data&gt;
                  &lt;PathGeometry x:Name="polylinePwr"&gt;
                      &lt;PathGeometry.Transform&gt;
                          &lt;ScaleTransform ScaleX="{Binding ActualWidth, ElementName=MeterCanvas}" ScaleY="{Binding ActualHeight, ElementName=MeterCanvas}" /&gt;
                      &lt;/PathGeometry.Transform&gt;
                      &lt;PathGeometry.Figures&gt;
                          &lt;PathFigure StartPoint="{Binding Path=thePoints[0], Converter={StaticResource pointCollectionConverter}}"&gt;
                              &lt;PathFigure.Segments&gt;
                                  &lt;PathSegmentCollection&gt;
                                      &lt;PolyLineSegment Points="{Binding thePoints, Converter={StaticResource pointCollectionConverter}}" /&gt;
                                  &lt;/PathSegmentCollection&gt;
                              &lt;/PathFigure.Segments&gt;
                          &lt;/PathFigure&gt;
                      &lt;/PathGeometry.Figures&gt;
                  &lt;/PathGeometry&gt;
              &lt;/Path.Data&gt;
          &lt;/Path&gt;
      &lt;/Canvas&gt;
      &lt;Label Content="{Binding thePoints[0]}" Margin="14,58,199.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/&gt;
      &lt;Label Content="{Binding thePoints[1]}" Margin="14,88,199.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/&gt;
      &lt;Label Content="{Binding thePoints[2]}" Margin="165,58,29.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/&gt;
      &lt;Label Content="{Binding thePoints[3]}" Margin="165,93,29.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/&gt;
  &lt;/Grid&gt;
  </code></pre>
  
  <p></p>
  
  <p>I am not really sure if I will gain any performance improvement, given the IValueConverter creates a new PointCollection Each the ObservableCollection is changed.</p>
  
  <p>THANK YOU everyone for helping me through this. I wanted to paste the complete code as working if any others run into the same thing.</p>
  
  <p><strong>EDIT #2</strong> - After benchmarking the Observable w/ IValueConverter vs. Copying PointCollection to a new PointCollection, the Point Collection seems faster:</p>
  
  <pre><code>    // Option 2 - WAY Faster.
      // Just Use a Points Collection, copy it, and add a point.
      public void AddPoint2(Point pt)
      {
          PointCollection pc = new PointCollection(_points2);
          pc.Add(new Point(pt.X, pt.Y));
          _points2 = pc;
          OnPropertyChanged("thePoints2");
      }
  </code></pre>
  
  <p>called from</p>
  
  <pre><code>            // 5000 point sinwave for testing
              foreach (Point pt in sinWave) mvm.AddPoint2(pt);
              x++;
  </code></pre>
  
  <p>If there is a better way, comments appreciated.</p>