Silverlight &WPF 技巧(一)DataGrid虚拟化加速不自动开启?

    在数据量大的情况下,DataGrid和ComboBox无法渲染或者渲染速度比较慢。

 首先我们来介绍下VirtualizingStackPanel 类(以下摘自MSDN)

         标准布局系统可以创建项容器并为每个与列表控件关联的项计算布局。 “虚拟化”是指一种技术,通过该技术,可根据屏幕上所显示的项来从大量数据项中生成用户界面 (UI) 元素的子集。 如果在可能只有少量元素显示在屏幕上时生成多个 UI 元素,则会对应用程序的性能产生负面影响。 VirtualizingStackPanel 会计算可见项的数量,并处理来自 ItemsControl(如 ListBoxListView)的 ItemContainerGenerator,以便只为可见项创建 UI 元素。

仅当 StackPanel 中包含的项控件创建自己的项容器时,才会在该面板中发生虚拟化。 可以使用数据绑定来确保发生这一过程。 如果创建项容器并将其添加到项控件中,则与 StackPanel 相比,VirtualizingStackPanel 不能提供任何性能优势。

VirtualizingStackPanel 是 ListBox 元素的默认项宿主。 默认情况下,IsVirtualizing 属性设置为 true。

当 IsVirtualizing 设置为 false 时,VirtualizingStackPanel 的行为与普通 StackPanel 一样。

VirtualizingStackPanel.VirtualizationMode 附加属性

VirtualizingStackPanel.VirtualizationMode 附加属性指定 ItemsControl 中的面板如何虚拟化其子项。 默认情况下,VirtualizingStackPanel 将为每个可见项创建一个项容器,并在不再需要时(比如当项滚动到视图之外时)丢弃该容器。 当 ItemsControl 包含多个项时,创建和废弃项容器的过程可能会对性能产生负面影响。 如果 VirtualizingStackPanel.VirtualizationMode 设置为 Recycling,VirtualizingStackPanel 将重用项容器,而不是每次都创建新的项容器。

如果 VirtualizingStackPanel 无法回收项容器,它会使用标准虚拟化模式,即为每个项创建和废弃项容器。 下面的列表描述了 VirtualizingStackPanel 无法回收项容器的几种情况:

当 VirtualizingStackPanel 回收项容器时,您可能需要保存与容器而不是与数据项本身关联的状态信息。 例如,如果 Expander 控件中包含项,则 IsExpanded 状态会绑定到项容器,而不是绑定到数据项本身。 当 Expander 重复用于新项时,IsExpanded 的当前值也用于该新项。 此外,旧项不保留其 IsExpanded 值。

正文开始啦

       在上面介绍中我们看到默认情况下虚拟化是开启的,并且虚拟化是只渲染可见部分的UI。我用如下代码做了个测试20列100行的数据DataGrid几乎渲染不出来

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition Height="25" ></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <Button Content="Load" Click="BtnLoadClick"></Button>
    <sdk:DataGrid Name="dataGrid" AutoGenerateColumns="True"
                  HorizontalAlignment="Left" Margin="10,10,0,0" Grid.Row="1"
                  VerticalAlignment="Top"/>
    <ComboBox Grid.RowSpan="2" Height="23" HorizontalAlignment="Left"
              Margin="10,10,0,0" Name="comboBox" Grid.Row="2" DisplayMemberPath="Name"
              SelectedValuePath="Id"  VerticalAlignment="Top" Width="120" />
</Grid>

             
我将代码改成将DataGrid所在Row改成了“*”

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition Height="25" ></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <Button Content="Load" Click="BtnLoadClick"></Button>
    <sdk:DataGrid Name="dataGrid" AutoGenerateColumns="True"
                  HorizontalAlignment="Left" Margin="10,10,0,0" Grid.Row="1"
                  VerticalAlignment="Top"/>
    <ComboBox Grid.RowSpan="2" Height="23" HorizontalAlignment="Left"
              Margin="10,10,0,0" Name="comboBox" Grid.Row="2" DisplayMemberPath="Name"
              SelectedValuePath="Id"
              VerticalAlignment="Top" Width="120" />
</Grid>

 DataGrid很快就渲染出来了,我们得出结论当高度为Auto的时候虚拟化被关闭,推测:虚拟化是渲染可见区域的UI,当控件为Auto的时候虚拟化将无法正常工作。当然在我的项目中很多地方都是高度自适应,虚拟化都被自动关闭了。当然只有在数据量比较大的情况下开启虚拟化才有效果,小数据事实上没有效果。

我们可以试试在Auto的情况下将虚拟化强制开启

<sdk:DataGrid Name="dataGrid" AutoGenerateColumns="True"
                    VirtualizingStackPanel.IsVirtualizing="True"
                     HorizontalAlignment="Left" Margin="10,10,0,0" Grid.Row="1"
                     VerticalAlignment="Top"/>

运行后报错:

image 事实上就是不报错,虚拟化也是很不起作用的。

总结:本文有点短(晚上有事要提前跑路啦),内容有点少。ComboxBox的虚拟化会加快打开下拉列表的速度,还有ListBox等朋友们可以参见MSDN:http://msdn.microsoft.com/zh-cn/library/system.windows.controls.virtualizingstackpanel.aspx

刚才的几行子代码下载

posted on 2011-02-22 15:50  Mr.Wrong居然被人用了  阅读(5688)  评论(14编辑  收藏  举报

导航