 <p>You might set <code>DoubleBuffered</code> to true on your control / form. Or you could try using your own Image to create a double buffered effect.</p> <p>My <code>DoubleBufferedGraphics</code> class:</p> <pre><code>public class DoubleBufferedGraphics : IDisposable { #region Constructor public DoubleBufferedGraphics() : this(0, 0) { } public DoubleBufferedGraphics(int width, int height) { Height = height; Width = width; } #endregion #region Private Fields private Image _MemoryBitmap; #endregion #region Public Properties public Graphics Graphics { get; private set; } public int Height { get; private set; } public bool Initialized { get { return (_MemoryBitmap != null); } } public int Width { get; private set; } #endregion #region Public Methods public void Dispose() { if (_MemoryBitmap != null) { _MemoryBitmap.Dispose(); _MemoryBitmap = null; } if (Graphics != null) { Graphics.Dispose(); Graphics = null; } } public void Initialize(int width, int height) { if (height &gt; 0 &amp;&amp; width &gt; 0) { if ((height != Height) || (width != Width)) { Height = height; Width = width; Reset(); } } } public void Render(Graphics graphics) { if (_MemoryBitmap != null) { graphics.DrawImage(_MemoryBitmap, _MemoryBitmap.GetRectangle(), 0, 0, Width, Height, GraphicsUnit.Pixel); } } public void Reset() { if (_MemoryBitmap != null) { _MemoryBitmap.Dispose(); _MemoryBitmap = null; } if (Graphics != null) { Graphics.Dispose(); Graphics = null; } _MemoryBitmap = new Bitmap(Width, Height); Graphics = Graphics.FromImage(_MemoryBitmap); } /// &lt;summary&gt; /// This method is the preferred method of drawing a background image. /// It is *MUCH* faster than any of the Graphics.DrawImage() methods. /// Warning: The memory image and the &lt;see cref="Graphics"/&gt; object /// will be reset after calling this method. This should be your first /// drawing operation. /// &lt;/summary&gt; /// &lt;param name="image"&gt;The image to draw.&lt;/param&gt; public void SetBackgroundImage(Image image) { if (_MemoryBitmap != null) { _MemoryBitmap.Dispose(); _MemoryBitmap = null; } if (Graphics != null) { Graphics.Dispose(); Graphics = null; } _MemoryBitmap = image.Clone() as Image; if (_MemoryBitmap != null) { Graphics = Graphics.FromImage(_MemoryBitmap); } } #endregion } </code></pre> <p>Using it in an <code>OnPaint</code>:</p> <pre><code>protected override void OnPaint(PaintEventArgs e) { if (!_DoubleBufferedGraphics.Initialized) { _DoubleBufferedGraphics.Initialize(Width, Height); } _DoubleBufferedGraphics.Graphics.DrawLine(...); _DoubleBufferedGraphics.Render(e.Graphics); } </code></pre> <p>ControlStyles I generally set if I'm using it (you may have different needs):</p> <pre><code>SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.DoubleBuffer, true); </code></pre> <p><strong>Edit:</strong></p> <p>Ok since the data is static you should paint to an Image (before your OnPaint) and then in the OnPaint use the <code>Graphics.DrawImage()</code> overload to draw the correct region of your source image to the screen. No reason to redraw the lines if the data isn't changing.</p>