Search code examples
c#graphicsinvalidationpaintevent

C#.NET .. is it a bad practice to draw outside the Paint event handler?


To clearup what I meant by my question.. I got used when making a game in C# using the .NET framework, to implement my own DrawScene() method and call it whenever I want to redraw the game's graphics (basically after any instance in the game has moved or changed its shape/state), like the following:

private void DrawScene()
{
    Graphics g = this.CreateGraphics();
    g.Clear(Color.Black);

    g.DrawImage(myBitmap, 0, 0);

    g.Dispose();
}

And by doing so, in my Paint event handler, all I do is the following:

private void Form1_Paint(object sender, PaintEventArgs e)
{
    DrawScene();
}

and for example, also when I want to redraw after the player makes some move, I simply call DrawScene() the same way:

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Keycode == Keys.Up)
    {
        hero.y -= 5;
    }

    DrawScene();
}

Is there any serious difference between doing that or doing it this way (Which I notice most people follow):

private void Form1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.Clear(Color.Black);

    e.Graphics.DrawImage(myBitmap, 0, 0);
}

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Keycode == Keys.Up)
    {
        hero.y -= 5;
    }

    this.Invalidate();
}

Sorry if this was much talking, but I just wanted to clear things up about my question..

So, if the two cases above does the drawing exactly the same way (From the Graphics viewpoint), and there's no harm keeping on my usual implementation as in the first case.. Then when is it best to use the invalidate() method?


Solution

  • This two approaches differs seriously (second one is preferred).

    First of all - in your approach you are creating new Graphics object each time you need to paint something, while in Paint event handler you're using the same graphics object each time.

    This increases memory usage (since redraws can occurs very frequently), and also since you're not disposing graphics you're creating (basically you should do it with any object implementing IDisposable you no longer need to use) - system resources used by graphics not being freed.

    Also, your form can be redrawed not manually by your call, but in some other cases (overlapping by other window, show/hide and so on). If your paintings will be done in Paint handler - then they will be done automatically, but in your "first" approach whey will not until you manually call your drawing method.

    So basically it is always better to paint everything in Paint event handlers (and call Invalidate or even Refresh to force redrawing) and not manually in separate methods.

    Sometimes (if your drawing takes much code and can be logically splitted into parts) it can be better to handle it like:

    private void DrawScene(Graphics g)
    {
        g.Clear(Color.Black);
        g.DrawImage(myBitmap, 0, 0);
    }
    
    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        DrawScene(e.Graphics);
        DrawSomething(e.Graphics);
    }
    

    So you still using grahics object from Paint event handler, but just passing it into drawing methods.