title: Simple animation using C#/Windows Forms
body: <p>I need to knock out a quick animation in C#/Windows Forms for a Halloween display.  Just some 2D shapes moving about on a solid background.  Since this is just a quick one-off project I <strong><em>really</em></strong> don't want to install and learn an entire new set of tools for this.  (DirectX dev kits, Silverlight, Flash, etc..)  I also have to install this on multiple computers so anything beyond the basic .Net framework (2.0) would be a pain in the arse.</p>
  
  <p>For tools I've got VS2k8, 25 years of development experience, a wheelbarrow, holocaust cloak, and about 2 days to knock this out.  I haven't done animation since using assembler on my Atari 130XE (hooray for page flipping and player/missile graphics!)</p>
  
  <p>Advice?  Here's some of the things I'd like to know:</p>
  
  <ul>
  <li>I can draw on any empty widget (like a panel) by fiddling with it's OnPaint handler, right?  That's how I'd draw a custom widget.  Is there a better technique than this?</li>
  <li>Is there a page-flipping technique for this kind of thing in Windows Forms?  I'm not looking for a high frame rate, just as little flicker/drawing as necessary.</li>
  </ul>
  
  <p>Thanks.</p>
  
  <p><strong>Post Mortem Edit ... "a couple of coding days later"</strong></p>
  
  <p>Well, the project is done.  The links below came in handy although a couple of them were 404.  (I wish SO would allow more than one reply to be marked "correct").  The biggest problem I had to overcome was flickering, and a persistent bug when I tried to draw on the form directly.</p>
  
  <ul>
  <li>Using the OnPaint event for the Form: bad idea.  I never got that to work; lots of mysterious errors (stack overflows, or ArgumentNullExceptions).  I wound up using a panel sized to fill the form and that worked fine.</li>
  <li>Using the OnPaint method is slow anyway.  Somewhere online I read that building the PaintEventArgs was slow, and they weren't kidding.  Lots of flickering went away when I abandoned this.  Skip the OnPaint/Invalidate() and just paint it yourself. </li>
  <li><p>Setting all of the "double buffering" options on the form still left some flicker that had to be fixed.  (And I found conflicting docs that said "set them on the control" and "set them on the form".  Well controls don't have a .SetStyle() method.)  I haven't tested without them, so they might be doing something (<code>this</code> is the form):</p>
  
  <pre><code>    this.SetStyle(ControlStyles.UserPaint, true);
      this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
      this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
  </code></pre></li>
  </ul>
  
  <p>So the workhorse of the code wound up looking like (<code>pf</code> is the panel control):</p>
  
  <pre><code>    void PaintPlayField()
      {
          Bitmap bufl = new Bitmap(pf.Width, pf.Height);
          using (Graphics g = Graphics.FromImage(bufl))
          {
              g.FillRectangle(Brushes.Black, new Rectangle(0, 0, pf.Width, pf.Height));
              DrawItems(g);
              DrawMoreItems(g);
              pf.CreateGraphics().DrawImageUnscaled(bufl, 0, 0);
          }
      }
  </code></pre>
  
  <p>And I just called PaintPlayField from the inside of my Timer loop.  No flicker at all.</p>