【问题标题】:What is the right way to use OnPaint in .Net applications?在 .Net 应用程序中使用 OnPaint 的正确方法是什么?
【发布时间】:2012-11-19 02:35:05
【问题描述】:

有时我需要控件的自定义外观。或者做很多定制绘画。我知道我可以通过 OnPaint 做到这一点(参见:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.onpaint.aspx

使用OnPaint 在您的.net 应用程序上自定义绘制内容的正确方法是什么?是否有任何规则我必须牢记以保持我的应用程序优化并尽量减少渲染时间?

注意:我不时看到并经历过很多 OnPaint 的低效使用,因此我创建了这个 Q&A。

【问题讨论】:

  • 我看到很多人做错了。为什么要结束这个问题?

标签: .net performance onpaint


【解决方案1】:

要有效地使用OnPaint,您必须了解以下几点:

  • 控件的OnPaint,例如Form1 的,每次绘制控件时都会执行(duhh...)
  • 每次绘制Form1子控件 时都会执行Form1OnPaint。例如如果使用Form1OnPaintForm1 的右上角绘制一个点,而Form1 上有150 个子控件,则该点将至少绘制150 次!它大大增加了渲染时间。特别是如果您在OnPaint 中进行大量自定义绘图和计算。
    • 因此,当一个控件有一个或多个子控件时,通常不能在控件的OnPaint 中包含任何逻辑。相反,您应该制作一个自定义控件,该控件上不再包含子控件,它可以完成绘制工作。并将其作为子控件放置在需要自定义绘图位置的父控件上。
    • 每当将控件添加到父级时,父级都会重绘。如果您将很多控件放在另一个控件上,例如在Form1 上带有复选框的大型结果集,您必须在添加子控件之前使用Form1.SuspendLayout()(请参阅:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.suspendlayout.aspx)。当您完成添加控件时,Form1.ResumeLayout()。这会暂时抑制 OnPaint 事件,并减少渲染时间。
    • 透明度总是会增加渲染时间。
    • 以这样一种方式放置组件,即它们之间没有背景,会减少父控件中OnPaint 事件的数量。例如。在彼此下方放置 4 个文本框,以便它们相互连接。因此它们之间没有背景,控件全部绘制在一个 OnPaint 事件中,而不是 4 个 OnPaint 事件中。当然,这并不总是可行的,因为您不想并排粘合所有组件。但是,如果性能比外观更重要,例如在某种大型自定义“数据网格”中,这样​​做是值得的。
    • 切勿在OnPaint 事件中更改控件的位置或大小,因为这会调用新的OnPaint 事件。如果您必须重新定位/调整控件大小,则必须在调用 OnPaint 之前将其添加到代码中的其他位置。例如,在OnLayoutOnResize 或类似事件中放置重定位/调整大小代码。如果您仍然认为必须将重定位/调整大小代码放在 OnPaint 事件中才能使您的应用程序正常工作,那么您就错了,您需要修改代码的逻辑。
    • 在其自身类之外的控件上调用 Refresh() 之前,请考虑 System.Math.Pow(2, 2) 次。如果您有调用 Refresh 的冲动,您可能需要新的事件和事件处理程序来与您愿意显示的内容保持同步。 Invalidate() 也是如此。
    • 要检查您的绘图是否有效,您可以执行以下操作。 1. 打开您的应用程序 2. 在 Top Most 父级的 OnPaint 上放置一个刹车点 3. 最大化一个窗口,使其覆盖您的应用程序。 4. 再次最小化窗口,您的应用程序将通过控件重绘控件。如果事情是双重的,那么你的应用程序逻辑就犯了一个错误。

好吧,我想就这些了,如果有什么我忘记了,我会更新这个问答。如果我忘记了什么,或者我犯了一个错误,我会很高兴注意到它!

希望这可以让某人在 .Net 中使用自定义绘画内容方面占得先机,因为我前段时间一直在寻找此信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-27
    相关资源
    最近更新 更多