Sometimes I need a custom appearence of a control. Or do alot of custom painting. I know I can do so with OnPaint
(see: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.onpaint.aspx)
What is the right way to custom paint stuff on your .net application using OnPaint
? Are there any rules I have to keep in mind to keep my application optimized, and keep render time to a minimum?
Note: I have seen, and experienced, a lot of inefficient uses of OnPaint from time to time, therefore I created this Q&A.
To use OnPaint
efficiently you have to know a couple things:
- The
OnPaint
of a control, e.g. ofForm1
, is executed everytime the control is painted (duhh...) - The
OnPaint
ofForm1
is executed everytime a child control ofForm1
is drawn. e.g. If you draw a dot in the upper right corner ofForm1
using theOnPaint
ofForm1
, while you have 150 child controls onForm1
, the dot will be drawn at least 150 times! It increases render time drastically. Especially if you do alot of custom drawing and calculations in theOnPaint
.- So as a rule you must never have any logic in the
OnPaint
of a control, when that control has one or more child controls. Instead you should make a custom control, which holds no more child controls on it, that does the paint job. And place that as a child control on the parent control on the location where the custom drawing is needed. - Whenever a control is added onto a parent, the parent will redraw. If you would place alot of controls on another control, e.g. a large result set with checkboxes on
Form1
, you must useForm1.SuspendLayout()
(see: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.suspendlayout.aspx) before you are adding the child controls. AndForm1.ResumeLayout()
when you are done adding controls. This temporarily supresses theOnPaint
event, and decreases render time. - Transparencies always increase render time.
- Placing components in such a way, that there is no background in between them, decreases the number of
OnPaint
events in the parent control. E.g. place 4 textboxes beneath eachother so that they thouch eachother. So there is no background in between them and the controls are all painted in oneOnPaint
event instead of 4OnPaint
events. Of course this is not always possible as you do not want to glue all your components side by side. But it is worth to do, if performance is more important than looks, for example in a large custom 'datagrid' of somekind. - NEVER change a location or the size of a control in the
OnPaint
event, as this invokes newOnPaint
events. If you must relocate/resize controls, you will have to add that somewhere else in your code, before theOnPaint
is invoked. For example, place relocation/resizing code in theOnLayout
orOnResize
or similar events. If you still think you must place that relocation/resizing code in theOnPaint
event in order for you application to work, than you are wrong, and you need to revise the logic of your code. - Think System.Math.Pow(2, 2) times before calling Refresh() on a control outside of its own class. If you have the urge to call Refresh you are probably in need of new events and event handlers to stay in sync with what you are willing to display. This is also the case for Invalidate().
- To check if you are drawing effenciently you can do the following. 1. Open you application 2. put a brake point on OnPaint in the Top Most parent 3. Maxamize a window so it covers your application. 4. Minimize the window again and you application will redraw control by control. If things are drawn double, you have made a mistake in the logic of you application.
- So as a rule you must never have any logic in the
Well I guess thats all, if something comes to mind that I forgot, i will update this Q&A. If I have forgotten something, or I made a mistake I would be glad to take note of it!
Hopefully this will give someone a headstart in using custom paint stuff in .Net, as I was looking for this information some time ago.
来源:https://stackoverflow.com/questions/13652568/what-is-the-right-way-to-use-onpaint-in-net-applications