zoukankan      html  css  js  c++  java
  • WPF Panel的性能分析

      大家知道WPF有多种Panel,如Canvas,Grid,StackPanel,DockPanel,WrapPanel,VirtualizingPanel等。

    在一些场景下可以选择任何一种或多种Panel实现一种效果。本文谈一下在同一场景下使用哪种Panel性能会更好。

      新建一个WPF项目,各放置Stackpanel,Canvas,Grid,看下所占的内存,如图1,2,3

                         图1 Grid

                        图2 Canvas

                        图3 StackPanel

    我们可以看到空内容情况下内存容量是StackPanel=Canvas<Grid。

    查看Panel类的OnRender方法,各类面板的性能差异主要体现在Render的过程中计算(Measure)排列(Arrange)不同容器内容的功能差异导致的性能消耗。

    大家有兴趣可以反编译.NET Framework,阅读下StackPanel,Canvas,Grid各自的MeasureOverride和ArrangeOverride方法。

    1.Measure和Arrange:

      在MeasureOverride方法里,影响性能的是自适应Arrange的属性。举例:HorizontalAlignment.Strech或Grid中ColumnDefinition的Width="Auto"。

    只要设置了这些属性,则Panel控件的子控件都将会拉伸或者自动计算大小。

      在ArrangeOverride方法里,影响性能的是不同的子控件在Panel位置之间的相互作用的复杂度以及子控件的数目。

    2.Panel类的派生

      在项目中有些特殊需求WPF现有提供的布局控件满足不了需求,这时候需要我们写自定义控件。举例:在ERP应用软件中大量的数据图表需要在UI显示,这时候

    我们需要在布局中显示类似HTML中TABLE 百分比的功能。两种做法:1.Binding副控件的实际大小通过Converter计算百分比 2.派生自布局控件重写功能

    如果使用方法1通过默认控件Binding,通过Memory Profiler看到其性能表现相当糟糕。

    使用方法2.继承自布局控件,其性能消耗小了很多。

    下面我们分别看下Grid,Canvas,StackPanel

    1.Grid:

      Grid定义一个可设置的的网格区域,可以将该网格区域分割成多行与多列。

      如果使用按比例(如:3*,7*)或者Auto调节行列大小,Grid 是一个性能损耗最严重的面板控件。

      原因是:当VisualTree上Child的原始大小和布局位置通过 Grid 来指定的时候,Child的区域大小计算非常复杂。同时,在所有Panel类型控件中,它的布局过程是最复杂的。

      性能评估:它的计算性能和排列性能属于中低水平。

    2.Canvas:

      Canvas定义了一个区域内的坐标系,Child可根据该坐标系决定处于布局中的绝对位置。

      Canvas 拥有在所有控件中最好的排列(Arrange)性能,在计算(Measure)步骤中也有很好的性能表现。

      原因是:针对Arrange,Canvas的所有Child位置都是绝对位置,是固定,直接指定的,Canvas并没有拉伸(Strech,Uriform,Fill etc...)的属性,所有Child都是使用自己的原始尺寸。

      性能评估:性能最好,无论是计算性能和排列性能。

    3.StackPanel:

      StackPanel定义了区域内的Child将按照水平方向或垂直方向排列成一行。

      在 StackPanel 内,Child的尺寸将如此计算:根据 StackPanel 的排列(Orientation)方向,如:垂直方向,则它的Child在水平方向的尺寸则使用原始尺寸或相对尺寸,而垂直方向的尺寸则使用原始尺寸(对齐属性在此方向并不影响它的尺寸)。由于它的排列(Arrange)步骤相对简单,只是将Child按顺序的逐个排列,所以它在这步骤的性能在所有Panel控件中排前列。

      性能评估:计算(Measure)性能属于中等水平,排列(Arrange)性能属于高等水平。

    代码:

     1 <Window x:Class="PerformanceDemo.MainWindow"
     2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4         Title="MainWindow" Height="350" Width="525">
     5     <!--<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
     6         <Grid.RowDefinitions>
     7             <RowDefinition Height="2*"></RowDefinition>
     8             <RowDefinition Height="Auto"></RowDefinition>
     9             <RowDefinition Height="Auto"></RowDefinition>
    10             <RowDefinition Height="Auto"></RowDefinition>
    11         </Grid.RowDefinitions>
    12         <Grid.ColumnDefinitions>
    13             <ColumnDefinition Width="3*"></ColumnDefinition>
    14             <ColumnDefinition Width="Auto"></ColumnDefinition>
    15         </Grid.ColumnDefinitions>
    16         <Label>Test</Label>
    17         <TextBlock Grid.Column="1">Test</TextBlock>
    18         <TextBlock Grid.Row="1" Grid.Column="0">Test</TextBlock>
    19         <TextBlock Grid.Row="1" Grid.Column="1">Test</TextBlock>
    20         <TextBlock Grid.Row="2" Grid.Column="0">Test</TextBlock>
    21         <TextBlock Grid.Row="2" Grid.Column="1">Test</TextBlock>
    22         <TextBlock Grid.Row="3" Grid.Column="0">Test</TextBlock>
    23         <TextBlock Grid.Row="3" Grid.Column="1">Test</TextBlock>
    24     </Grid>-->
    25     <!--<StackPanel Orientation="Horizontal">
    26         <Label>Test</Label>
    27         <TextBlock>Test</TextBlock>
    28         <TextBlock>Test</TextBlock>
    29         <TextBlock>Test</TextBlock>
    30         <TextBlock>Test</TextBlock>
    31         <TextBlock>Test</TextBlock>
    32         <TextBlock>Test</TextBlock>
    33         <TextBlock>Test</TextBlock>
    34     </StackPanel>-->
    35     <Canvas>
    36         <Label Canvas.Left="10" Canvas.Top="5">Test</Label>
    37         <TextBlock Canvas.Right="100" Canvas.Top="15">Test</TextBlock>
    38         <TextBlock Canvas.Right="90" Canvas.Top="25">Test</TextBlock>
    39         <TextBlock Canvas.Right="80" Canvas.Top="35">Test</TextBlock>
    40         <TextBlock Canvas.Right="70" Canvas.Top="45">Test</TextBlock>
    41         <TextBlock Canvas.Right="60" Canvas.Top="55">Test</TextBlock>
    42         <TextBlock Canvas.Right="50" Canvas.Top="65">Test</TextBlock>
    43         <TextBlock Canvas.Right="40" Canvas.Top="75">Test</TextBlock>
    44     </Canvas>
    45 </Window>

    截图,如图4,5,6:

                        图4 Grid

                        图5 Canvas

                       图6 StackPanel

    结论:

      布局过程的复杂性直接取决于使用的 Panel 派生元素的布局行为。 例如,Grid 或 StackPanel 控件提供的功能比 Canvas 控件多很多。 功能大大提高的代价是性能成本也大大提高。 但是,如果不需要 Grid 控件提供的功能,则应使用成本较低的布局控件,如 Canvas 或自定义面板。

    参考资料:

    http://msdn.microsoft.com/zh-cn/library/bb613542.aspx

    http://msdn.microsoft.com/zh-cn/library/ms745058.aspx#LayoutSystem_Measure_Arrange

    前面查了下,附上Framework源码下载地址:

    http://referencesource.microsoft.com/netframework.aspx

    如果大家觉得不错请帮我点下推荐,谢谢~

    转载时,请注明本文来源:www.cnblogs.com/tmywu

    作者:Tommywu

    邮箱:tommywu23@126.com

     

  • 相关阅读:
    Elastic-Job分布式任务调度
    java.sql.BatchUpdateException: ORA-01861: 文字与格式字符串不匹配
    oracle锁表和解锁
    sql ibatis
    唯一索引
    斐波那契数列
    旋转数组的最小数字
    两个栈来实现一个队列
    重建二叉树
    重写和重载
  • 原文地址:https://www.cnblogs.com/tmywu/p/3075331.html
Copyright © 2011-2022 走看看