Best practice for custom control painting in Winforms?
Normally when I override the OnPaint method, I create pens and brushes, etc inside it and then dispose them.
I also read somewhere that instead o开发者_开发技巧f recreating these pens and brushes, etc to create them once as static members, and then dispose them once when the form is closed, etc.
Is this a better practice?
Is there a better way for this?
I can assume that since OnPaint is called 1000s (?) of times, that would create a lot of work for the GC compared to creating them only once.
If the brushes and pens don't change, it's certainly better to create them once and reuse them. Note, however, that if your control might be used on multiple threads (which is very unlikely), you should either make them ThreadStatic
(and initialize on first use per thread) or make them instance members (and dispose them in your control's Dispose
override); otherwise, you'll get unreproducable GDI+ errors, as GDI+ objects cannot be used on multiple threads at once. The same is true for images.
If the they do change (for example, if you use gradient brushes which depend on the control's size), you might still want to store them in instance fields, and recreate them when the control's size (or whatever) changes.
Note, by the way, that if you use normal colors, you can use the static Brushes
and Pens
classes, which contain static brushes and pens for all of .Net's built-in colors, and SystemBrushes
and SystemPens
for system colors.
I read an interesting article last month which suggested doing all of your painting onto a separate BufferedGraphics object, and have the on_paint method do a straight copy from that to your control's graphics object.
That way, the on-paint is faster, and you only update your BufferedGraphics when something significant changes (i.e. a line moves or text changes).
What I'd do is have the brushes and pens as members of the custom control, then dispose them when disposing of the control. This way you reuse the same brush/pen every time OnPaint is called.
I wouldn't declare them static
though, because you wouldn't be able to know when you can dispose of your objects. But as SLaks mentioned, if there are many instances of the control in memory at the same time, it can be a good idea to create brushes and pens as static so that you have only one instance of each object created for the lifetime of your application.
I really depends on what are you painting. If you will paint something that is repainted only as a result of an user interaction, you can loose your performance worries and create all of the graphic objects ad-hoc i.e. when needed.
Make sure that you Dispose()
everything you need in your graphics. Pens, Brushes, Regions, Fonts. Those are all GDI objects and are tied into system by GDI handles.
If you need graphics that is animated in some way or will change in time without user clicking it, prepare all your graphic objects in front and reuse them as much as you can. Rule that can be applied here is that is better to waste memory then milliseconds in drawing every frame of the animation.
An lastly, at least for this post - don't forget to use double-buffering, either automatic in .net Control system or roll-your-own-back-bitmap style.
Have fun GDI-ing :)
A best practice would be to use system pens and brushes, as these are optimized for minimal resources consumption.
精彩评论