How do I reduce high CPU usage because of a C# Windows forms custom control being redrawn frequently?

StackOverflow https://stackoverflow.com/questions/21177341

Pergunta

Ogmo Editor is a nice open source 2D map editor written in C# which unfortunately has a high CPU usage problem - whenever you open the actual level editing screen it completely saturates a single CPU core. I looked into the source and after profiling it came to the conclusion that the OnPaint handler of the LevelEditor custom control is being called repeatedly. I am not very familiar with the Windows Forms API and checked the MSDN documentation about custom controls but was unable to determine the source of the problem.

I then looked into another similar open source project called tIDE which to me seems to be rendering its editing screen - the MapPanel control in a very similar manner - please see the OnMapPaint() function definition in the link for details.

I am not sure why the control should refresh when it is not changing, I think someone familiar with the API may be able to suggest a solution.

Foi útil?

Solução 2

The problem was the following code in the level editor file:

 void Application_Idle(object sender, EventArgs e)
 {
      Invalidate();
      LevelView.Update();
 }

The Application Idle event occurs just before the application is about to become idle and this resulted in an infinite redraw loop which is very processor intensive. Removing the Invalidate() call required updating the code to redraw whenever a user interaction occurs, this required changes to multiple files in the project and the resulting commit can be seen here on Bitbucket.

For anyone else having similar issues the problem of excessive redraws is likely to be caused because of changes to the control or manual Invalidate() calls.

Outras dicas

Try this. Derive your own CustomLevelEditor from OgmoEditor.LevelEditors.LevelEditor. Then override the OnPaint event like this.

    protected override void OnPaint(PaintEventArgs e) {
        base.OnPaint(e);
        System.Threading.Thread.Sleep(1);
    }

Sleeping for 1ms in the UI thread between paint events will bring the CPU cycles down significantly. If OnPaint gets fired by the base control non-stop, then you might try something like this.

    int paintReps = 0;

    protected override void OnPaint(PaintEventArgs e) {
        base.OnPaint(e);
        System.Threading.Thread.Sleep(1);

        if(paintReps++ % 500 == 0)
            Application.DoEvents();
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top