提高 WPF UI 渲染速度的方法
Posted
技术标签:
【中文标题】提高 WPF UI 渲染速度的方法【英文标题】:Ways to improve WPF UI rendering speed 【发布时间】:2011-07-21 01:38:28 【问题描述】:如果 WPF 应用程序的屏幕包含大量原始控件,则其呈现会变得缓慢。在这种情况下,除了添加更少的控件和使用更强大的显卡之外,还有哪些推荐的方法来提高 WPF 应用程序的响应能力?
有没有办法以某种方式使用屏幕外缓冲或类似的东西?
【问题讨论】:
WPF 中的分层/透明窗口的性能很糟糕。这是 UI 渲染最常见的问题。 blogs.msdn.com/b/dwayneneed/archive/2008/09/08/…有关一般性能优化指南,请参阅:msdn.microsoft.com/en-us/library/aa970683.aspx 你能给出一些数字吗?每个窗口的控件数量等。 @NVM 实际上,现在每个窗口大约有一千个自定义控件(自定义控件由几个边框、文本块和大约几十个依赖属性组成)。控件的数量可以增加。但是这个数量已经需要一些令人不舒服的秒数才能在初始渲染中可视化。此外,它在放大时不会提供很好的平滑滚动。 我发现很难在用户面前同时可视化包含一千个文本框的 UI。无论如何,根据一切的安排方式,您可以使用内置的虚拟化面板之一,也可以编写自己的自定义面板,它只会创建可见的控件。这应该会大大加快速度。 @NVM 感谢您指出虚拟化面板的潜在用途。由于元素的特定布局,我不确定它是否适合我的特殊情况,但我会注意这一点。 【参考方案1】:我们的团队面临渲染性能问题。在我们的例子中,我们有大约 400 个运输单元,我们应该渲染每个单元的图表,其中包含很多细节(文本标签、特殊标记、不同的几何形状等)。
在我们的实现中,我们首先将每个图表拆分为基元,并通过绑定组成整个单元的图表。这是非常悲伤的经历。 UI 反应非常缓慢。
因此我们决定为每个单元创建一个 UI 元素,并使用DrawingContext 渲染图表。尽管这在性能方面要好得多,但我们花了大约一个月的时间来改进渲染。
一些建议:
-
缓存所有内容。画笔、颜色、几何图形、格式化文本、字形。 (例如我们有两个类:
RenderTools
和TextCache
。每个单元地址的渲染过程到两个类的共享实例。所以如果两个图表有相同的文本,它的准备只执行一次。)
如果您打算长期使用它,请冻结Freezable
。尤其是几何形状。复杂的未冻结几何图形执行 HitTest 非常慢。
选择渲染每个图元的最快方式。比如文字渲染的方式大概有6种,但最快的是DrawingContext.DrawGlyphs
。
使用分析器发现热点。例如,在我们的项目中,我们有几何图形缓存并按需渲染它们。似乎,没有任何改进是可能的。但是有一天我们想,如果我们一次渲染几何图形并缓存准备好的视觉效果会怎样?在我们的案例中,这种方法是可以接受的。我们单位的图表只有几个状态。当图表的数据发生变化时,我们为每个状态重建 DrawingVisual 并将它们放入缓存中。
当然,这种方式需要一些投资,工作枯燥乏味,但效果很棒。
顺便说一句:当我们打开 WPF 缓存选项(您可以在答案中找到链接)时,我们的应用程序挂断了。
【讨论】:
我知道这篇文章有点老了,但我想知道你用什么方法来缓存画笔、颜色等等。我觉得如果我知道如何做到这一点,我可能会避免一些滞后。 Here 我上传了我的 RenderTools 对象的简化版本。 here 是使用示例。如果您仍有疑问,请随时提出。 非常感谢。我会看看他们。【参考方案2】:一年以来,我在高度定制的数据网格中遇到了同样的性能问题,我的结论是:
基本上你无能为力 在你身边(不影响你 应用程序,即:控制较少或 仅使用默认样式)
Jens 提到的链接很棒,但在你的情况下没用。
根据我的经验,NVM 提供的“优化 WPF 应用程序性能”链接几乎同样无用:它只是诉诸常识,我相信您不会学到任何特别的东西。 可能除了一件事:我必须说这个链接教会了我在我的应用程序资源中尽可能多地投入。因为 WPF 不会重新实例化您放入资源中的任何内容,它只是一遍又一遍地重用相同的资源。所以尽可能多地放在那里(样式、画笔、模板、字体......)
总而言之,仅通过选中一个选项或关闭另一个选项,根本无法在 WPF 中让事情变得更快。你可以祈祷微软在不久的将来重做他们的渲染层来优化它,同时尽量减少你对效果、自定义控件等的需求......
【讨论】:
【参考方案3】:看看新的 (.NET 4.0) 缓存选项。 (见here。)
【讨论】:
不是只针对 Silverlight 吗? @mark:不,不是。我在 WPF 项目中使用过它。您可以单击链接页面中的“其他版本”链接以查看其他支持的框架。【参考方案4】:我遇到了类似的问题,想分享我的想法和发现。最初的问题是由一个显示大约 25 个复杂控件的虚拟化列表框引起的(一个带有文本块的网格和显示一些路径的几个按钮) 为了研究这个问题,我使用了 VisualStudio 应用程序时间线,它允许渲染每个控件和 PerfView 需要多少时间来找出 WPF 实际在做什么来渲染每个控件。 默认情况下,渲染每个项目大约需要 12 毫秒。如果您需要动态更新列表,则相当长。 由于WPF在父子层次结构中呈现项目,因此很难使用PerfView来分析内部发生的事情,但是我对内部流程有了共同的理解。 WPF 执行以下操作来呈现列表中的每个项目:
-
使用 XAML 阅读器解析模板。据我所知,XAML 解析是最大的问题。
应用样式
应用绑定
应用样式和绑定并不需要很多时间。
为了提高性能,我做了以下操作:
-
每个按钮都有自己的模板,渲染它需要很长时间。我用边框替换了按钮。之后渲染每个项目大约需要 4-5 毫秒。
将所有元素设置移动到样式。大约 3 毫秒。
在模板中使用单个网格创建自定义项控件。我在代码中创建所有子元素并使用 TryFindResources 方法应用样式。结果大约需要 2 毫秒。
在所有这些更改之后,性能看起来不错,但大部分时间仍然花在加载 ListControl.Item 模板和自定义控件模板上。 4.最后一步:用Canvas和Scrollbar控件替换一个ListControl。现在所有项目都是在运行时创建的,并且位置是使用 MeasureOverride 和 ArrangeOverride 方法手动计算的。现在渲染每个项目需要
我仍然使用样式和绑定,因为它们在数据更改时不会对性能产生太大影响。您可以想象这不是 WPF 解决方案。但是我在应用程序中喜欢一些类似的列表,并且可以根本不使用模板。
【讨论】:
以上是关于提高 WPF UI 渲染速度的方法的主要内容,如果未能解决你的问题,请参考以下文章