大家知道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