【问题标题】:In what order are Panels the most efficient in terms of render time and performance?面板在渲染时间和性能方面的效率最高的顺序是什么?
【发布时间】:2012-03-30 16:23:16
【问题描述】:

很多时候,不止一个面板适合我想要的布局,但是我知道不同面板类型的渲染时间存在差异。

例如,MSDN 声明

一个比较简单的Panel,比如Canvas,可以显着 比更复杂的Panel 性能更好,例如Grid

那么就渲染时间和性能而言,WPF 面板按什么顺序最高效?

WPF 面板:

  • Canvas
  • DockPanel
  • Grid
  • UniformGrid
  • StackPanel
  • WrapPanel
  • VirtualizingPanel / VirtualizingStackPanel

我很确定我在网上某处看到了这个列表,但我现在找不到。

我正在寻找的理想答案会按照它们呈现最快的顺序为我提供一个面板列表。我知道孩子的数量是面板效率的一个重要因素,所以为了这个问题,假设每个面板只有一个 Label/TextBox 对。

此外,我想要一个例外列表,例如在某些条件下表现优于其他面板的特定面板。

更新

根据下面的accepted answer总结,面板性能是基于子项的数量和布局,但总体上从最快到最慢的列表是:

  • Canvas
  • StackPanel
  • WrapPanel
  • DockPanel
  • Grid

此外,如果有很多项目并不总是适合屏幕,则应始终使用VirtualizingPanel / VirtualizingStackPanel

我强烈建议您阅读下面的accepted answer 了解更多详细信息,然后再从该列表中选择一个项目。

【问题讨论】:

  • 假设虚拟化面板总是比非虚拟化面板表现更好是不是太天真了?
  • @BoltClock 我认为这取决于面板中有多少不可见的内容。如果有很多不可见的项目,VirtualizingStackPanel 肯定会表现得更好,但如果面板中显示的所有项目都是可见的,我认为使用常规面板更好。
  • 谢谢。确实有道理,将项目虚拟化是一种浪费,因为无论如何它们都会显示。
  • 除了虚拟化之外,它们具有不同的功能,否则它们将不是单独的控件。我选择为客户提供最佳 UI 的东西。
  • 你确定有明显的区别(除了虚拟化)吗?他们所要做的就是执行一个相对轻量级的布局算法。与接下来的所有渲染相比,微不足道。话虽如此,网格可能是最慢的(加权缩放)。

标签: wpf performance rendering panel


【解决方案1】:

我认为描述每个面板的性能特征比尝试给出绝对的相对性能比较更简洁易懂。

WPF 在呈现内容时会进行两次传递:测量和排列。对于这两个通道中的每一个,每个面板都有不同的性能特征。

measure pass 的性能受面板使用对齐方式(或自动,在Grid 的情况下)的能力以及被拉伸或自动调整大小的子项数量的影响最大。 Arrange pass 的性能受不同children的布局位置之间交互的复杂性影响,当然还有children的数量。

有时给定的面板不容易适应所需的布局。我创建了一个控件,该控件需要任意数量的项目,每个项目都位于可用空间的一定百分比。没有任何默认控件执行此操作。试图让它们这样做(通过绑定到父级的实际大小)会导致糟糕的性能。我创建了一个基于 Canvas 的布局面板,它以最少的工作达到了我想要的结果(我复制了画布的源代码并修改了大约 20 行)。

可用面板:

  • 画布

    定义一个区域,您可以在其中明确定位子项 元素按相对于 Canvas 区域的坐标。

    由于每个项目都静态分配了一个位置,因此 Canvas 在排列通道的所有面板中具有最佳性能。由于此面板中没有拉伸的概念,因此测量通道也具有出色的性能;每个孩子只使用其原始尺寸。

  • DockPanel

    定义一个区域,您可以在其中排列子元素 水平或垂直,相对于彼此。

    Dockpanel 有一个非常简单的布局方案,其中项目相对于前一个添加的项目一个接一个地添加。默认情况下,高度或宽度由项目的原始大小确定(分别基于上/下与左/右),如果未定义宽度或高度,则另一个方向由Dock 属性确定。中到快速测量通过和中到快速排列通过。

  • 网格

    定义由列和行组成的灵活网格区域。

    如果使用按比例调整大小或自动调整大小,这可能是性能最密集的面板。计算子项大小可以是项的本机大小和网格指定的布局的复杂组合。布局也是所有面板中最复杂的。测量传递的性能慢到中等,排列传递的性能慢到中等。

  • 堆栈面板

    将子元素排列成可以定向的单行 水平或垂直。

    StackPanel 使用与其方向相反的方向上的本机或相对大小以及在其方向上的本机大小(对齐在此方向上不做任何事情)来测量其子项。这使其成为该领域的中级执行者。安排通行证很简单,只是按顺序排列项目。可能是本次传球的第二好表现。测量传递的中等性能和布局传递的快速性能。

  • 虚拟化面板

    为虚拟化其子数据集合的 Panel 元素提供框架。这是一个抽象类。

    实现您自己的虚拟化面板的基类。仅加载可见项目以防止不必要地使用内存和处理器。对于项目集的性能要高得多。由于边界检查,适合屏幕的项目的性能可能略低。 SDK 只提供了一个子类,VirtualizingStackPanel

  • WrapPanel

    将子元素按从左到右的顺序放置,将内容分到包含框边缘的下一行。随后的排序顺序发生 从上到下或从右到左,取决于 方向属性。

    measure pass 是一个有点复杂的 pass,其中特定行的最大项目决定了行的高度,然后该行上的每个项目要么使用其原生高度(如果有的话)要么使用行的高度。布局过程很简单,将每个项目一个接一个地放在一行上,然后在没有足够空间容纳下一个项目时继续到下一行。中等绩效衡量通过。安排传递的中到快速性能。

参考资料:

尽可能使用最高效的面板

布局过程的复杂程度直接取决于布局 您使用的面板派生元素的行为。例如,网格或 StackPanel 控件提供了比 Canvas 更多的功能 控制。这种更大的功能增加的代价是 性能成本增加更大。但是,如果您不需要 Grid 控件提供的功能,您应该使用 成本较低的替代品,例如画布或自定义面板。

来自Optimizing Performance: Layout and Design

布局系统为 Children 的每个成员完成两次传递 收集,测量通行证和排列通行证。每个子面板 提供自己的 MeasureOverride 和 ArrangeOverride 方法 实现自己特定的布局行为。

在测量过程中,Children 集合的每个成员都是 评估。该过程从调用 Measure 方法开始。这 在父面板的实现中调用方法 元素,并且不必为布局显式调用 发生。

首先,评估 UIElement 的原生大小属性,例如 剪辑和可见性。这会生成一个名为 constraintSize 的值 传递给 MeasureCore。

其次,在 FrameworkElement 上定义的框架属性是 处理,这会影响constraintSize的值。这些属性 一般描述底层证券的规模特征 UIElement,例如它的高度、宽度、边距和样式。这些中的每一个 属性可以更改显示所需的空间 元素。然后使用 constraintSize 作为 MeasureOverride 调用 参数。

注意Height和Width的属性是有区别的 和实际高度和实际宽度。例如,实际高度 属性是基于其他高度输入的计算值,并且 布局系统。该值由布局系统本身设置,基于 实际的渲染过程,因此可能会稍微落后于 设置属性的值,例如高度,它们是 输入变化。因为 ActualHeight 是一个计算值,所以您应该 请注意,可能存在多个或增量报告的更改 作为布局系统的各种操作的结果。这 布局系统可能正在计算孩子所需的测量空间 元素,父元素的约束,等等。终极的 测量通过的目标是让孩子确定其 DesiredSize,在 MeasureCore 调用期间发生。所需尺寸 值由 Measure 存储,以在内容排列过程中使用。

排列过程从调用 Arrange 方法开始。在此期间 排列传递,父面板元素生成一个矩形 代表孩子的界限。这个值被传递给 ArrangeCore 方法进行处理。

ArrangeCore 方法评估孩子的 DesiredSize 和 评估任何可能影响渲染大小的附加边距 元素。 ArrangeCore 生成一个arrangeSize,传递给 Panel 的 ArrangeOverride 方法作为参数。 ArrangeOverride 生成孩子的 finalSize。最后, ArrangeCore 方法对偏移属性进行最终评估,例如 作为边距和对齐方式,并将子项放在其布局槽中。 孩子不必(而且经常不会)填满整个 分配的空间。然后控制权返回到父面板和 布局过程完成。

来自Measuring and Arranging Children

【讨论】:

  • 回应现在删除的评论:我没有包含指标,因为它们没有帮助。电子表格的组合太多而无用。优化性能的一个更有用的方法是使用一般理解来选择初始布局面板,然后通过对实际情况的分析从那里根据需要进行优化。
  • 谢谢您,您解释了 WPF 面板是如何实际呈现的,并且每个面板的测量/排列性能都比我要求的要好得多 :)
  • @mydogisbox 我在你的列表中没有看到UniformGrid。您能否使用该面板更新您的答案以及与其他面板类型相关的估计测量/排列性能?
  • @Rachel UniformGrid 不适用于应用程序布局。请参阅此处的“派生面板元素”:msdn.microsoft.com/en-us/library/ms754152.aspx 了解更多信息。速度方面,它应该比DockPanel 稍快,比Canvas 稍慢。
【解决方案2】:

也许this 会帮助你。

不仅适用于面板,还适用于您想在 WPF 中制作的每个应用程序。

它结束了 WPF 绘图和测量性能。

它还有一个绘图测试应用程序、结果和结论信息,适用于您想要定位的不同操作系统。

【讨论】:

    【解决方案3】:

    您提到的面板是布局面板,因此对布局系统的简要概述表明,它可能不仅仅是最有效面板的简单列表,而是您如何使用对效率和性能影响最大的面板.

    LayoutSystem_Overview

    在最简单的情况下,布局是一个递归系统,它导致元素被调整大小、定位和绘制。更具体地说,布局描述了测量和排列 Panel 元素的 Children 集合的成员的过程。布局是一个密集的过程。 Children 集合越大,必须进行的计算次数就越多。也可以根据拥有该集合的 Panel 元素定义的布局行为引入复杂性。相对简单的面板(例如 Canvas)可以比更复杂的面板(例如网格)具有更好的性能。

    每次子 UIElement 更改其位置时,它都有可能触发布局系统的新传递。因此,了解可以调用布局系统的事件非常重要,因为不必要的调用会导致应用程序性能下降。下面描述调用布局系统时发生的过程。

    1。 子 UIElement 通过首先测量其核心属性来开始布局过程。

    2。 评估在 FrameworkElement 上定义的大小调整属性,例如 Width、Height 和 Margin。

    3。 应用特定于面板的逻辑,例如 Dock 方向或堆叠方向。

    4。 内容是在所有孩子都测量完后安排的。

    5。 Children 集合被绘制在屏幕上。

    6。 如果向集合中添加了额外的 Children、应用了 LayoutTransform 或调用了 UpdateLayout 方法,则会再次调用该过程。

    请参阅LayoutSystem_Measure_Arrange 了解有关儿童测量和安排的更多信息

    LayoutSystem_Performance

    布局是一个递归过程。 Children 集合中的每个子元素都会在布局系统的每次调用期间得到处理。因此,应避免在不必要时触发布局系统。以下注意事项可以帮助您获得更好的性能。

    注意哪些属性值更改将强制布局系统进行递归更新。

    其值可以导致布局系统被初始化的依赖属性用公共标志标记。 AffectsMeasure 和 AffectsArrange 提供了有用的线索,说明哪些属性值更改将强制布局系统进行递归更新。通常,任何可能影响元素边界框大小的属性都应将 AffectsMeasure 标志设置为 true。有关详细信息,请参阅依赖属性概述。

    如果可能,请使用 RenderTransform 而不是 LayoutTransform。

    LayoutTransform 是影响用户界面 (UI) 内容的一种非常有用的方法。但是,如果变换的效果不必影响其他元素的位置,最好使用 RenderTransform 代替,因为 RenderTransform 不会调用布局系统。 LayoutTransform 应用其转换并强制递归布局更新以说明受影响元素的新位置。

    避免对 UpdateLayout 的不必要调用。

    UpdateLayout 方法强制进行递归布局更新,并且通常不是必需的。除非您确定需要完全更新,否则请依靠布局系统为您调用此方法。

    处理大型 Children 集合时,请考虑使用 VirtualizingStackPanel 而不是常规 StackPanel。

    通过虚拟化子集合,VirtualizingStackPanel 仅将当前位于父 ViewPort 中的对象保留在内存中。因此,在大多数情况下,性能都会得到显着提高。

    Optimizing Performance: Layout and Design: 本文详细介绍了如何有效地构建树,并根据其复杂性给出了一个简单的面板列表

    Canvas(最简单 = 更高效和更好的性能)

    网格

    其他面板(更复杂 = 效率更低且性能更差)

    其他需要注意的性能注意事项: Ways to improve WPF UI rendering speed

    1. 缓存所有内容。画笔、颜色、几何图形、格式化文本、字形。 (例如我们有两个类:RenderTools 和 TextCache。每个单元地址的渲染过程到两个类的共享实例。所以如果两个图表有相同的文本,它的准备只执行一次。)
    2. Freeze Freezable,如果您打算长期使用它。尤其是几何形状。复杂的未冻结几何图形执行 HitTest 非常慢。
    3. 选择每个基元的最快渲染方式。例如,文本渲染的方式大约有 6 种,但最快的是 DrawingContext.DrawGlyphs。
    4. 启用容器回收。虚拟化带来了很多性能提升,但是容器会被销毁并重新创建,这是默认的。但是您可以通过设置 VirtualizingStackPanel.VirtualizationMode="Recycling"
    5. 来回收容器来获得更多性能
    6. 来自here:您的应用程序可以支持的嵌套数量没有实际限制,但是,通常最好将您的应用程序限制为仅使用您想要的布局实际需要的那些面板。在许多情况下,可以使用 Grid 元素代替嵌套面板,因为它作为布局容器具有灵活性。这可以通过将不必要的元素排除在树之外来提高应用程序的性能。

    【讨论】:

    • 这个答案几乎完全包括从其他来源复制和粘贴,其中一些来源未注明出处。如果您将其缩减为仅相关部分,正确归因所有来源并尝试更直接地回答问题,那就更好了。
    • @mydogisbox 答案是信息汇编,我可能会补充说,您在答案中使用了许多相同的网站。为了不考虑改变性能的其他方面可能导致不完整的答案或提问者仍有其他问题,所以我选择将它们包括在内。虽然拥有惊人的 21.7K 代表和大量 WPF 经验的 Rachel 可能已经知道这些信息,但其他正在查看此问题的人可能希望获得这些额外且相关的信息以及答案。
    猜你喜欢
    • 2013-01-12
    • 2014-03-31
    • 1970-01-01
    • 1970-01-01
    • 2019-08-07
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多