Já jsem to dělal tak, že jsem přímo na bitmapu (Bitmap) kreslil a v událost Paint jsem ji vykresloval na obrazovku.. Akorát tam byl menší problém s blikáním té bitmapy při překreslování..to jsem nevyřešil..

Vytvoříš si někde bitmapu
Kód:
Bitmap bmp = new Bitmap(640, 480);
Pro kreslení na bitmapu potřebuješ Graphics objekt, pokud nechceš kreslit pomocí SetPixel..
Kód:
Graphics g = Graphics.FromImage( bmp );
Vykreslíš něco na bitmapu přes Graphics objekt a uvolníš ho..
Kód:
g.DrawLine(....);
g.Dispose();
Teď máš něco v bitmapě..po nakreslení potřebuješ bitmapu dostat na obraz..např. na nějaký Panel..
Kód:
MyPanel.Invalidate();
MyPanel.Update();
Událost Paint pro panel...
Kód:
void MyPanel_Paint(Object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;
    g.DrawImage( bmp, 0, 0 );
    g.Dispose();
}
Teď máš bitmapu vykreslenou na panelu...
Jde optimalizovat volání Invalidate tak, že se bude nastavovat pro překreslení jen určitá oblast..ta, na které bylo kresleno...mrkni na metodu Invalidate a její parametry...

Možná to jde udělat i jinak..nějak že by se na bitmapu ukládalo jen v případě nutnosti, ale to jsem nezkoumal..
Pokud chceš, můžu ti poslat svoje malování (ale mám to trochu jiné..kreslím hlavně přes SetPixel pomocí algoritmů jako DDA, Scan line flood fill a tak).

Btw kreslení perem se dělá tak, že nakreslíš bod a pak kreslíš od předchozí pozice čáru k další pozici..budeš tak mít spojitou čáru a ne jednotlivé body