在.Net应用程序中,使用OnPaint的正确方法是什么?

3
有时我需要自定义控件的外观或进行大量的自定义绘画。我知道可以使用OnPaint来实现(请参见:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.onpaint.aspx)。
在您的.NET应用程序中使用OnPaint进行自定义绘画的正确方法是什么?是否有任何规则需要记住,以保持应用程序优化,并将渲染时间最小化?
注意:我曾经看到和经历过许多低效的OnPaint使用情况,因此我创建了这个问答。

我看到很多人做错了这件事。为什么要关闭这个问题? - Mike de Klerk
1个回答

11

要有效使用 OnPaint,您需要了解以下几点:

  • 控件(如 Form1)的 OnPaint 在每次绘制控件时执行。
  • Form1OnPaint 在每次绘制 子控件 时执行。例如,如果您在 Form1OnPaint 中在右上角绘制一个点,并且在该控件上有 150 个子控件,则会至少绘制 150 次!这会显著增加渲染时间,特别是如果您在 OnPaint 中进行大量自定义绘制和计算时。
    • 因此,在控件的 OnPaint 中绝不能有任何逻辑,当该控件有一个或多个子控件时。相反,您应该创建一个不包含子控件的自定义控件,来完成绘制工作。并将其作为子控件放置在需要自定义绘制的父控件上。
    • 每当将控件添加到父控件上时,父控件都会重新绘制。如果您将很多控件(例如带有复选框的大型结果集)放在另一个控件上,您必须在添加子控件之前使用 Form1.SuspendLayout()(请参见:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.suspendlayout.aspx),并在添加控件完成后使用 Form1.ResumeLayout()。这会暂时抑制 OnPaint 事件并减少渲染时间。
    • 透明度总是增加渲染时间。
    • 在放置组件时,应使它们紧密贴合以减少父控件中的背景数量,从而减少OnPaint事件的数量。例如,将4个文本框放在彼此下方,使它们互相接触,这样它们之间就没有背景,所有控件都会在一个OnPaint事件中绘制而不是4个OnPaint事件中分别绘制。当然,这并不总是可能的,因为您不想把所有组件都黏在一起。但是,如果性能比外观更重要(例如在某种大型自定义“datagrid”中),这是值得做的。
      永远不要在OnPaint事件中更改控件的位置或大小,因为这会引发新的OnPaint事件。如果您必须重新定位/调整控件的大小,则必须在OnPaint被调用之前将其添加到代码的其他位置。例如,在OnLayoutOnResize等事件中放置重新定位/调整大小的代码。如果您仍然认为必须将该重新定位/调整大小的代码放置在OnPaint事件中,以使您的应用程序工作,则是错误的,并且需要修订您的代码逻辑。
      在对控件类外部调用Refresh()之前,请三思而后行。如果您有刷新的冲动,您可能需要新的事件和事件处理程序以保持与您想要显示的内容同步。这也适用于Invalidate()。
      为了检查您是否有效地绘制,可以执行以下操作。1.打开您的应用程序2.在最顶层父级上将断点放在OnPaint处3.最大化窗口,使其覆盖您的应用程序。4.再次最小化窗口,您的应用程序将逐个重新绘制控件。如果事物被画两次,则说明您的代码逻辑存在错误。

      好的,如果我忘记了什么,会更新这个问答。 如果我遗漏了什么或犯了错误,我很乐意注意到它!

      希望这能为某些人在使用.NET中的自定义绘图方面提供一个起点,就像我一段时间以前寻找这些信息一样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接