English 中文(简体)
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 of 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.





相关问题
Bring window to foreground after Mutex fails

I was wondering if someone can tell me what would be the best way to bring my application to the foreground if a mutex was not able to be created for a new instance. E.g.: Application X is running ...

How to start WinForm app minimized to tray?

I ve successfully created an app that minimizes to the tray using a NotifyIcon. When the form is manually closed it is successfully hidden from the desktop, taskbar, and alt-tab. The problem occurs ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

Handle DataTable.DataRow cell change event

I have a DataTable that has several DataColumns and DataRow. Now i would like to handle an event when cell of this DataRow is changed. How to do this in c#?

Apparent Memory Leak in DataGridView

How do you force a DataGridView to release its reference to a bound DataSet? We have a rather large dataset being displayed in a DataGridView and noticed that resources were not being freed after the ...

ALT Key Shortcuts Hidden

I am using VS2008 and creating forms. By default, the underscore of the character in a textbox when using an ampersand is not shown when I run the application. ex. "&Goto Here" is not ...

WPF-XAML window in Winforms Application

I have a Winforms application coded in VS C# 2008 and want to insert a WPF window into the window pane of Winforms application. Could you explain me how this is done.

热门标签