title: Terrible performance of custom-drawn control
body: <p>I am making simple graph control in <code>wpf</code>. And I can't explain nor fix performance problem: it's too slow compared to winforms. Perhaps I am doing something wrong.</p>
  
  <p>I prepare demo to demonstrate the problem.</p>
  
  <p>Here is test control:</p>
  
  <pre><code>public class Graph : FrameworkElement
  {
      private Point _mouse;
      private Point _offset = new Point(500, 500);
  
      public Graph()
      {
          Loaded += Graph_Loaded;
      }
  
      private void Graph_Loaded(object sender, RoutedEventArgs e)
      {
          // use parent container with background to receive mouse events too
          var parent = VisualTreeHelper.GetParent(this) as FrameworkElement;
          if (parent != null)
              parent.MouseMove += (s, a) =&gt; OnMouseMove(a);
      }
  
      protected override void OnRender(DrawingContext context)
      {
          // designer bugfix
          if (DesignerProperties.GetIsInDesignMode(this))
              return;
  
          Stopwatch watch = new Stopwatch();
          watch.Start();
  
          // generate some big figure (try to vary that 2000!)
          var radius = 1.0;
          var figures = new List&lt;LineSegment&gt;();
          for (int i = 0; i &lt; 2000; i++, radius += 0.1)
          {
              var segment = new LineSegment(new Point(radius * Math.Sin(i) + _offset.X, radius * Math.Cos(i) + _offset.Y), true);
              segment.Freeze();
              figures.Add(segment);
          }
          var geometry = new PathGeometry(new[] { new PathFigure(figures[0].Point, figures, false) });
          geometry.Freeze();
          var pen = new Pen(Brushes.Black, 5);
          pen.Freeze();
          context.DrawGeometry(null, pen, geometry);
  
          // measure time
          var time = watch.ElapsedMilliseconds;
          Dispatcher.InvokeAsync(() =&gt;
          {
              Window.GetWindow(this).Title = string.Format("{0:000}ms; {1:000}ms", time, watch.ElapsedMilliseconds);
          }, DispatcherPriority.Loaded);
      }
  
      protected override void OnMouseMove(MouseEventArgs e)
      {
          base.OnMouseMove(e);
          var mouse = e.GetPosition(this);
          if (e.LeftButton == MouseButtonState.Pressed)
          {
              // change graph location
              _offset.X += mouse.X - _mouse.X;
              _offset.Y += mouse.Y - _mouse.Y;
              InvalidateVisual();
          }
          // remember last mouse position
          _mouse = mouse;
      }
  }
  </code></pre>
  
  <p>Here is how to use it in xaml:</p>
  
  <pre><code>&lt;Window x:Class="WpfApplication1.MainWindow"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:local="clr-namespace:WpfApplication1"
          Title="MainWindow" Height="350" Width="525" WindowState="Maximized"&gt;
      &lt;Grid Background="White"&gt;
          &lt;local:Graph/&gt;
      &lt;/Grid&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p>Some remarks: control will draw figure, which can be moved by mouse:</p>
  
  <p><img src="https://i.stack.imgur.com/XKqBN.png" alt="enter image description here"></p>
  
  <p>It will display 2 measurements in title: first is how long it took for <code>OnRender()</code> to complete and second one is how long actual rendering took (first invoke after render).</p>
  
  <p>Try to vary that <code>2000</code>: setting <code>1000</code> makes <em>moving</em> comfortable, <code>3000</code> is like half-second delay before figure is redrawn (on my PC).</p>
  
  <p>Questions:</p>
  
  <ol>
  <li>Is it good to use <code>InvalidateVisual()</code> to update graph offset in <code>MouseMove</code>? And if bad, what is the right technique to invalidate?</li>
  <li>Freezes, there are many of them without any noticeable effect. Do I need to use them or not?</li>
  <li>It looks like it takes only <code>5ms</code> to complete render, but moving subjectively takes much longer (200ms+). Why is that?</li>
  </ol>
  
  <p>And main question is of course performance, why is it so terrible? I could draw few hundred thousands of lines in winform control until it become as sloppy, as mine wpf control does with just 1000... =(</p>
  
  <hr>
  
  <p>I found an answer on last question. Measuring of rendering time doesn't works correctly when moving with mouse. But if window is resized, then second time become <code>300ms</code> (on my PC with <code>2000</code> figures). So it's not a <em>wrong mouse invalidate</em> (first question), but indeed very slow rendering.</p>