title: Why is Wpf's DrawingContext.DrawText so expensive?
body: <p>In Wpf (4.0) my listbox (using a VirtualizingStackPanel) contains  500 items. Each item is of a custom Type </p>
  
  <pre><code>class Page : FrameworkElement
  ...
  protected override void OnRender(DrawingContext dc)
  {
     // Drawing 1000 single characters to different positions
     //(formattedText is a static member which is only instantiated once and contains the string "A" or "B"...)
     for (int i = 0; i &lt; 1000; i++)
       dc.DrawText(formattedText, new Point(....))
  
  
    // Drawing 1000 ellipses: very fast and low ram usage
      for (int i = 0; i &lt; 1000; i++)     
      dc.DrawEllipse(Brushes.Black, null, new Point(....),10,10)
  
  
  }
  </code></pre>
  
  <p>Now when moving the scrollbar of the listbox back and forth so that every item's visual is created at least once the ram usage goes up  to 500 Mb after a while and then - after a while - goes back to ca 250 Mb but stays on this level. Memory leak ? I thought the advantage of a VirtualizingStackPanel is that visuals which are not needed/visible get disposed... </p>
  
  <p>Anyway, this extreme ram usage only appears when drawing text using "DrawText". Drawing other objects like "DrawEllipse" does not consume so much memory. </p>
  
  <p><strong>Is there a more efficient way to draw many text items than using Drawing.Context's "DrawText" ?</strong></p>
  
  <p>Here is the complete sample (just create a new Wpf Application project and replace the window1 code): (I know there are FlowDocument and FixedDocument but they are no alternative)
  Xaml:</p>
  
  <pre><code>&lt;Window x:Class="WpfApplication1.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="Window1" Height="900" Width="800"&gt;
  &lt;Grid Background="Black"&gt;
      &lt;ListBox Name="lb" ScrollViewer.CanContentScroll="True"   Background="Black"&gt;
          &lt;ListBox.ItemsPanel&gt;
              &lt;ItemsPanelTemplate&gt;
                  &lt;VirtualizingStackPanel Orientation="Horizontal" /&gt;
              &lt;/ItemsPanelTemplate&gt;
          &lt;/ListBox.ItemsPanel&gt;
      &lt;/ListBox&gt;
  &lt;/Grid&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p>And the Window1.xaml.cs:</p>
  
  <pre><code>public partial class Window1 : Window
  {
      readonly ObservableCollection&lt;FrameworkElement&gt; collection = new ObservableCollection&lt;FrameworkElement&gt;();
  
    public Window1()
      {
          InitializeComponent();
  
          for (int i = 0; i &lt; 500; i++)
          {
              collection.Add(new Page(){ Width = 500, Height = 800 });
          }
  
          lb.ItemsSource = collection;
      }
  }
  
   public class Page : FrameworkElement
  {
      static FormattedText formattedText = new FormattedText("A", CultureInfo.GetCultureInfo("en-us"),
                                                FlowDirection.LeftToRight,
                                                new Typeface(new FontFamily("Arial").ToString()),
                                                12,Brushes.Black);
      protected override void OnRender(DrawingContext dc)
      {
          dc.DrawRectangle(Brushes.White, null, new Rect(0, 0, Width, Height));
          double yOff = 0;
          for (int i = 0; i &lt; 1000; i++) // draw 1000 "A"s 
          {
              dc.DrawText(formattedText, new Point((i % 80) * 5, yOff ));
              if (i % 80 == 0) yOff += 10;
  
          }
  
      }
  
  }
  </code></pre>