精通 WPF UI Virtualization

简介:

   本篇博客主要说明如何使用 UI Virtualization(以下简称为 UIV) 来提升 OEA 框架中 TreeGrid 控件的性能,同时,给出了一些学习 UIV 的资源。

 

 

问题


    最近对 OEA 的 TreeGrid 控件进行了比较大的改造,并使用新的控件来替换了系统中所有的 DataGrid 控件。新的 TreeGrid 控件实现了很多新的功能,(之后会写一篇文章说明),但是最后遗留了一个问题:由于使用它替换了原来的 DataGrid,而 DataGrid 默认是支持 UI Virtualization 的,当有些界面的数据量比较大时,没有支持 UIV 的TreeGrid 控件就显得有些力不从心了。为了解决这个问题,这两天看了许多文章并学习了 WPF 中 UIV 的知识,在最后终于解决了,待写下此文予以记录。

    先来看看实现 UIV 前:

image

518 条数据,生成了 18130 个 Visuals。

 

其实,在解决完后看来,问题主要出在 TreeGrid 的 Template 上,直接贴上来给大家看看:

<ScrollViewer Style="{StaticResource GridTreeViewScroll}" Background="{TemplateBinding Background}"
Focusable="false"
CanContentScroll="false"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
<Grid>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
<TextBlock Opacity="0.5" TextWrapping="Wrap" FontSize="36" Text="没有数据" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" FontFamily="STCaiyun" RenderTransformOrigin="0.5,0.5" Foreground="#80000000">
<TextBlock.Visibility>
<MultiBinding>
<MultiBinding.Converter>
<oeaModuleWPF:ItemsControlNoDataConverter/>
</MultiBinding.Converter>
<Binding Path="Data" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type oea:GridTreeView}}"/>
<Binding Path="Items.Count" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type oea:GridTreeView}}"/>
</MultiBinding>
</TextBlock.Visibility>
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.5"/>
<SkewTransform AngleX="-30"/>
<RotateTransform Angle="-30"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
</Grid>
</ScrollViewer>

 

    其中,为了实现在列表没有数据时,显示 “没有数据” 四个字,使用了一个 Grid 包含了一个 ItemsPresenter 以及一个 TextBlock。这段代码看上去没有什么问题,所以搞了很久都没有把 UIV 调试出来,最终只有在网上耐心学习了很我 UIV 的相关知识。

 

 

解决方案


     其实, 相关的 UIV 知识点 有那么几个:

 

  1. WPF 中的 VirtualizingStackPanel 只支持一层数据的 UIV。(这一点好像在 WPF3.5 SP1 后有所改善?)
  2. WPF3.5 SP1 以前的 TreeView 是不支持 UIV的。而之后的 TreeView 在默认情况下 UIV 处于关闭状态,需要手动打开。
  3. 实现 UIV 需要一个对应的 ScollViewer。
  4. ScollViewer 中的 CanContentScroll 属性为 True 时,子对象才能实现 UIV。
    该属性为 True 时,ScollViewer 在 Measure 时会把当前的 ViewPort 大小传给 Content 元素。否则,它会把 Infinite 传给 Content。
    同时,由子元素(也就是 VirtualizingStackPanel)需要实现 IScollInfo 并返回 Scroll 相关信息,而 ScollViewer 则只是一个简单的视窗;这样,子元素就可以在内部实现 UIV,并告知其对应的 ScrollOwner(ScrollViewer) 相关的拖动信息。

    所以,上面的 xaml 主要有两个错误:

  1. ScrollViewer.CanContentScroll 应该设置为 True。
  2. 应该把 VirtualizingStackPanel 作为 ScrollViewer 的内容元素(Content)。

修改为以下 xaml 即可:

<Grid>
<ScrollViewer Style="{StaticResource GridTreeViewScroll}" Background="{TemplateBinding Background}"
Focusable="false"
CanContentScroll="{TemplateBinding ScrollViewer.CanContentScroll}"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
<VirtualizingStackPanel IsItemsHost="True" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
<TextBlock Opacity="0.5" TextWrapping="Wrap" FontSize="36" Text="没有数据">……</TextBlock>
</Grid>
 

同时,注意打开 TreeView 的 UIV 支持:

public class GridTreeView : TreeView
{
static GridTreeView()
{
VirtualizingStackPanel.IsVirtualizingProperty.OverrideMetadata(typeof(GridTreeView), new FrameworkPropertyMetadata(true));
}
 

来看看优化后的结果:

image

Visuals 的数量由 1W8 降到了 3000,当行数更多时,也就保持初始生成 3000 个左右。拖动起来也明显地感觉到流畅了许多。

大功告成!


本文转自BloodyAngel博客园博客,原文链接:http://www.cnblogs.com/zgynhqf/archive/2011/12/12/2284335.html,如需转载请自行联系原作者

相关文章
|
16天前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
|
2月前
|
前端开发 C# 索引
浅谈WPF之UI布局
一个成功的软件,离不开人性化的UI设计,如何抓住用户第一视觉,让用户产生依赖感,合适优雅的布局必不可少。本文以一些简单的小例子,简述WPF中布局 面板 控件的使用,仅供学习分享使用,如有不足之处,还请指正。
38 1
|
3月前
|
搜索推荐 C# 开发者
3个值得推荐的WPF UI组件库
3个值得推荐的WPF UI组件库
152 0
|
3月前
|
前端开发 JavaScript C#
一个WPF版的Layui前端UI库
一个WPF版的Layui前端UI库
|
4月前
|
搜索推荐 C#
一个适用于定制个性化界面的WPF UI组件库
一个适用于定制个性化界面的WPF UI组件库
|
16天前
|
C# 开发者 C++
一套开源、强大且美观的WPF UI控件库
一套开源、强大且美观的WPF UI控件库
130 0
|
8月前
|
设计模式 编解码 前端开发
WPF技术之UI框架介绍
WPF(Windows Presentation Foundation)是微软公司开发的一种用于创建Windows应用程序的UI框架。它是.NET框架的一部分,是Windows Vista及更高版本操作系统的默认UI框架。
2060 0
WPF技术之UI框架介绍
WPF常用UI库和图标库(MahApps、HandyControl、LiveCharts)
WPF有很多开源免费的UI库,本文主要介绍常见的MahApps、HandyControl两个UI库;在开发过程中经常会涉及到图表的开发,本文主要介绍LiveCharts开源图表库。
|
C# C++ Windows
VS进行Revit插件UI开发时缺少WPF项
VS进行Revit插件UI开发时缺少WPF项
VS进行Revit插件UI开发时缺少WPF项
|
Linux C# Docker
推荐一款基于.Net Core开发简约漂亮的 WPF UI库
这是一款使用简单、UI评论的WPF UI库,借鉴了多个开源框架。UI简单清晰、大气。
777 0
推荐一款基于.Net Core开发简约漂亮的 WPF UI库