Windows Develop Bookmark and Share   
 index > Windows Forms General > OnPaint called very frequently on UserControl
 

OnPaint called very frequently on UserControl

Hi all,

I have a small problem with painting UserControls.
My control is part of a scrollable list and as such an overriden OnPaint function is called when it comes into view. The problem is that it seems to get called several times, presumably causing very inefficient drawing.
The callstack shows the same trace every time onpaint gets accessed, it looks like this:

> Console.exe!Overlord.TaskControl.OnPaint(System.Windows.Forms.PaintEventArgs e = {ClipRectangle = {X=4,Y=4,Width=894,Height=108}}) Line 1633 C#
  System.Windows.Forms.dll!System.Windows.Forms.Control.PaintTransparentBackground(System.Windows.Forms.PaintEventArgs e, System.Drawing.Rectangle rectangle, System.Drawing.Region transparentRegion = null) + 0x16c bytes
  System.Windows.Forms.dll!System.Windows.Forms.Control.PaintBackground(System.Windows.Forms.PaintEventArgs e = {ClipRectangle = {X=0,Y=0,Width=894,Height=108}}, System.Drawing.Rectangle rectangle, System.Drawing.Color backColor, System.Drawing.Point scrollOffset) + 0xbc bytes
  System.Windows.Forms.dll!System.Windows.Forms.Control.PaintBackground(System.Windows.Forms.PaintEventArgs e, System.Drawing.Rectangle rectangle) + 0x63 bytes
  System.Windows.Forms.dll!System.Windows.Forms.Control.OnPaintBackground(System.Windows.Forms.PaintEventArgs pevent) + 0x59 bytes
  System.Windows.Forms.dll!System.Windows.Forms.ScrollableControl.OnPaintBackground(System.Windows.Forms.PaintEventArgs e) + 0x37 bytes
  System.Windows.Forms.dll!System.Windows.Forms.TableLayoutPanel.OnPaintBackground(System.Windows.Forms.PaintEventArgs e = {ClipRectangle = {X=0,Y=0,Width=894,Height=108}}) + 0x39 bytes
  System.Windows.Forms.dll!System.Windows.Forms.Control.PaintWithErrorHandling(System.Windows.Forms.PaintEventArgs e = {ClipRectangle = {X=0,Y=0,Width=894,Height=108}}, short layer, bool disposeEventArgs = true) + 0x74 bytes
  System.Windows.Forms.dll!System.Windows.Forms.Control.WmEraseBkgnd(ref System.Windows.Forms.Message m = {msg=0x14 (WM_ERASEBKGND) hwnd=0x40ce0 wparam=0xffffffffd7011f00 lparam=0x0 result=0x0}) + 0xd2 bytes
  System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) + 0x309 bytes
  System.Windows.Forms.dll!System.Windows.Forms.ScrollableControl.WndProc(ref System.Windows.Forms.Message m) + 0x2a bytes
  System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) + 0x10 bytes
  System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x31 bytes
  System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg = 0x00000014, System.IntPtr wparam, System.IntPtr lparam) + 0x57 bytes
  [Native to Managed Transition]
  user32.dll!7e418734()
  [Frames below may be incorrect and/or missing, no symbols loaded for user32.dll]
  user32.dll!7e418816()
  user32.dll!7e428ea0()
  user32.dll!7e428eec()
  ntdll.dll!7c90e473()
  user32.dll!7e4193e9()
  user32.dll!7e4193a8()
  [Managed to Native Transition]
  System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID, int reason = 0xffffffff, int pvLoopData = 0x00000000) + 0x17d bytes
  System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason = 0xffffffff, System.Windows.Forms.ApplicationContext context = {System.Windows.Forms.ApplicationContext}) + 0x177 bytes
  System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x61 bytes
  System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.Form mainForm) + 0x31 bytes
  Console.exe!Overlord.Program.Main() Line 37 + 0xb bytes C#
  mscoree.dll!79007c24()
  kernel32.dll!7c817077()

Is there a way of avoiding the multiple calls (8 times!) to improve speed?

Thanks in advance


Glacial  Tuesday, October 06, 2009 11:25 AM
There is only one paint call in your stack trace.  Don't mistake the nested virtual method calls for individual paint events.  They only take a few nanoseconds.

Hans Passant.
nobugz  Tuesday, October 06, 2009 12:33 PM
Sorry maybe I wasn't clear...
The OnPaint method is called 8 times, EACH TIME the stack is as above when a breakpoint in the function is hit suggesting the trigger for the paint is the same each time.
Glacial  Tuesday, October 06, 2009 12:58 PM
OnPaint gets called alot regardless.  Move the window - OnPaint gets called.  Move your mouse over the control - OnPaint gets called.   Switch foreground windows - OnPaint gets called.

In fact, it's called whenever it needs to repaint itself.  It's just a fact of life.

Your only hope here is to make OnPaint as efficient as possible by choosing a good algorithm.  A bad one can slow you down immensely.
Coding Light - Illuminated Ideas and Algorithms in Software
Coding Light Wiki �LinkedIn �ForumsBrowser
David M Morton  Tuesday, October 06, 2009 1:03 PM
The OnPaint method is called 8 times, EACH TIME the stack is as above when a breakpoint in the function is hit suggesting the trigger for the paint is the same each time.
This is entirely normal when you debug your program.  The breakpoint will put Visual Studio in the foreground.  When you resume, the control will have to be repainted again, triggering the breakpoint again.  That's an endless cycle you'll only break when you remove the breakpoint.  Which I assume you did after 8 times.

Hans Passant.
nobugz  Tuesday, October 06, 2009 1:34 PM
Ok the debugging point is a good one... but after a while it did sort itself, after 8 times. Instead of a break point I added a Trace call which still shows 8 individual OnPaint calls. And it seems to do it 8 times everytime it needs to repaint.
In the end I just want to improve the UI speed.
Resizing also seems to be a bit of a slow process. Any tips on a good method to resizing the list and all the controls within?

Thanks!
Glacial  Tuesday, October 06, 2009 2:14 PM
I would suggest you use a double-buffered member level image variable to paint on. Actions requiring UI representation can draw directly to the image and the paint method should do nothing more than render the image in it's current state.

The goal is to move as much "processing" code out of the OnPaint as possible and only include rendering code.

HTH
"There's a way to do it better - find it." - Thomas Edison
Derik Palacino  Tuesday, October 06, 2009 5:38 PM

You can use google to search for other answers

Custom Search

More Threads

• Does anyone know how to implement IComponent?
• HOW TO GET TCP/IP OF ALL ONLINE COMPUTER IN INTERANET
• Sharing DataSet with child UserControl
• XP Style problems with treeview
• Print without Print DialogBox
• ShowDialog
• Weird behavior when adding to WritePrivateProfileString parameters.
• passing data between 2 datagridviews
• Updating ListViewItems from DataChanged Events
• Attachment