WPF的UI虚拟化

许多时候,我们的界面上会呈现大量的数据,如包含数千条记录的表格或包含数百张照片的相册。由于呈现UI是一件开销比较大的动作,一次性呈现数百张照片就目前的电脑性能来说是需要占用大量内存和时间的。因此需要对其进行优化。以前采用的方案大多数是翻页,翻页在某种程度上造成用户浏览的中断,因此现在往往采用一种新的方案——UI虚拟化。

UI虚拟化的原理是:但是由于显示器和人眼的限制,用户往往只会同时看到其中的数十条数据,因此只要在界面上渲染用户所看到的那些数据即可,对于用户呈现的界面仍然是一样的。微软的MSDN文档UI虚拟化说明的比较详细,这里就不累述了。

关于UI虚拟化的实现,其核心则是VirtualPanel,在WPF中内置的VirtualPanel貌似只有VirtualizingStackPanel一个,不过这个也是最实用的,一般常用于表格之类的数据呈现。如果需要其它布局方式的Panel,则需要自己实现,MSDN Blog上有一系列文章介绍得比较详细:

  1. Implementing a VirtualizingPanel part I
  2. Implementing a VirtualizingPanel part II
  3. Implementing a VirtualizingPanel part III
  4. Implementing a VirtualizingPanel part IV

文章最后也附带了一个VirtualizingTilePanel,实现了一个类似WrapPanel的效果(它要求里面的元素大小是相等的)。用于照片浏览之类的持续还是比较方便的,不知道为什么M$官方没有带这个。原文的.Net版本比较老,是直接编译不过去的,需要自行修改一下。

实现自定义VirtualizingPanel并非很复杂,首先介绍介绍几个前置条件:

1. VirtualizingPanel是用于UI虚拟化的,它是用来做ItemsControl的ItemTemplate的,而不是像普通Panel那样直接控制Children。因此,它必须同ItemsControl及其子类(如DataGrid、ListBox)搭配使用,并继承自VirtualizingPanel。

2. VirtualizingPanel是需要和ScrollViewer一起使用的,没有ScrolViewer的话,所有控件都是可见的,谈不上虚拟化。需要注意的是,ItemsControl的默认Template没有ScrollViewer,在ItemsControl中使用VirtualizingPanel时,需要修改一下Template,加上ScrollViewer,并设置CanContentScroll="True"。

3. UI虚拟化是需要在不呈现所有的UI控件前提下知道当前视图下元素呈现效果的,如果所有的数据都转换了为控件的话,也就谈不上虚拟化了。也就是说,不能靠Measure和Arrange所有子元素来确定布局。

具体实现的时候一般有如下几个功能点:

  1. Panel需要实现IScrollInfo接口,这样才能手动控制滚动时候的界面虚拟化。关于IScrollInfo接口,我前面的文章中有一些介绍,可以参考一下。
  2. Panel需要能只根据数据感知整体的布局。常见的有三种方案:1. 在Panel中直接指定每个子元素所占据的空间大小,2. 拿第一个子元素所占据的大小来衡量其它子元素所占据的大小,3.数据中直接声明它所需要的大小
  3. Panel根据当前窗口的大小呈现元素(加载可见元素,删除不可见元素)。

例子就可以直接参考前面的那个,这里就不单独举例了。

数据虚拟化:

UI虚拟化可以解决渲染UI控件所需要较多的时间和内存的问题,但是还是有可以优化的空间,那就是所有的数据仍然都加载到了内存中了。我们仍然可以采用和UI虚拟化一样的优化方案:不加载所有数据到集合,只加载用户可见部分。数据虚拟化本身并不受WPF所支持,不过当我们的Panel实现IScrollInfo接口了之后,就可以精确感知滚动条了,实现数据虚拟化也不是难事。

一般来说,我们很少使用数据虚拟化,主要的原因是它大多数的时候只能减少很少一点内存占用,反而带来了较大的代码复杂度, 一般是认为得不偿失的。

不过,有的时候,我们的数据是来自于外部RPC访问,这个时候数据虚拟化就有意义了,考虑如下两个场景:

  1. 新闻客户端,数据来源是来自于远程的Rest服务,但是它的接口是分页获取的,只能每次获取50条,总共却可能有100页。
  2. 图片浏览器,图片不是来自于本地,而是来自于图片服务网站。

第一个例子就是比较典型的数据虚拟化的应用场景了,如果一开始就加载所有100页新闻就需要花费大量时间了。第二个例子则是部分数据虚拟化,图片信息无需虚拟化,但图片呈现需要虚拟化,只是在需要呈现的时候才从网络下载。

时间: 2024-12-05 21:10:30

WPF的UI虚拟化的相关文章

WPF之UI虚拟化

原文:WPF之UI虚拟化 在WPF应用程序开发过程中,大数据量的数据展现通常都要考虑性能问题.有下面一种常见的情况:原始数据源数据量很大,但是某一时刻数据容器中的可见元素个数是有限的,剩余大多数元素都处于不可见状态,如果一次性将所有的数据元素都渲染出来则会非常的消耗性能.因而可以考虑只渲染当前可视区域内的元素,当可视区域内的元素需要发生改变时,再渲染即将展现的元素,最后将不再需要展现的元素清除掉,这样可以大大提高性能. 对于ListBox,在XAML Template中加入以下属性 Scroll

WPF listbox UI虚拟化

ListBox  默认是UI虚拟化的. 1. 原生使用 <ListBox VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling"> </ListBox> 为ListBox 设置一个ItemTemplate <DataTemplate x:Key="ListBoxDataTemplate">

wpf 客户端【JDAgent桌面助手】开发详解(三) 瀑布流效果实现与UI虚拟化优化大数据显示

目录区域: 业余开发的wpf 客户端终于完工了..晒晒截图 wpf 客户端[JDAgent桌面助手]开发详解-开篇 wpf 客户端[JDAgent桌面助手]详解(一)主窗口 圆形菜单... wpf 客户端[JDAgent桌面助手]开发详解(二)桌面宠物制作详解 因为前段时候有很多的事情 比较忙,自从上次写完博客之后很久没有更新了. 用WPF制作的京东桌面助手.这个作品是参加比赛的,自己花费了很多心思和时间在里面,最终的作品效果和比赛的结果还是令人满意的. 作品感觉不说很fashion,也足够细致

WPF多线程UI更新——两种方法

WPF多线程UI更新--两种方法 前言 在WPF中,在使用多线程在后台进行计算限制的异步操作的时候,如果在后台线程中对UI进行了修改,则会出现一个错误:(调用线程无法访问此对象,因为另一个线程拥有该对象.)这是很常见的一个错误,一不小心就会有这个现象.在WPF中,如果不是用多线程的话,例如单线程应用程序,就是说代码一路过去都在GUI线程运行,可以随意更新任何东西,包括UI对象.但是使用多线程来更新UI就可能会出现以上所说问题,怎么解决?本文章提供两个方法:Dispatcher(大部分人使用),T

WPF Modern UI 主题更换原理

WPF Modern UI 主题更换原理 一 . 如何更换主题? 二 . 代码分析 代码路径 : FirstFloor.ModernUI.App / Content / SettingsAppearance.xaml 1.关键 XAML 代码 <ComboBox Grid.Row="1" Grid.Column="1" ItemsSource="{Binding Themes}" SelectedItem="{Binding Se

从0 开始 WPF MVVM 企业级框架实现与说明 ---- 第七讲 WPF 系统UI结构说明与AvalonDock的使用

说到WPF UI, 现在网上到处都有现成的UI, 我觉得还是AvalonDock算是比较适合企业级系统点,一般向ModernUI之类的只能做做小的App还凑合这用. 这边我分享一个DLL, AvalonDock.dll 访问密码 2f90 , 你们可以去下载,后面我们的demo中就是用这样一种UI结构. 其实对于一个系统的设计,我们要考虑到整体的业务逻辑,数据结构,业务需求与拓展等各方面,我这主要还是分模块一步步慢慢介绍下去,没有具体的项目,我就分模块去慢慢介绍. 这里就说Avalondock的

WPF 列表开启虚拟化的方式

正确开启虚拟化的方式 列表如ListBox,ListView,TreeView,GridView等,开启虚拟化 ScrollViewer设置CanContentScroll=True 直接在模板中,设置CanContentScroll="True" 如模板中未设置CanContentScroll属性,可以在列表添加属性ScrollViewer.CanContentScroll="True". 注意:如果在模板中设置CanContentScroll="Fal

c#跨线程、跨类更新WinForm、WPF 进度UI

两个委托,一个委托(delegate)将值传到WinForm类,另一个委托(Action)更新UI using System; using System.Windows.Forms; using System.Threading; namespace UpdateUIDemo { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } int p = 0; //声明一个委托,用来改变进

WPF 模拟UI 键盘录入

开发WinForm 应用程序时可以利用SendKeys 类方便的模拟键盘录入操作.那么在WPF 中如何为控件实现键盘模拟呢?本篇将使用WPF SendKeys 实现和WinForm 中相同的效果. 首先将WpfSendKeys.dll 加入到项目References 中,在XAML 中加入两个Textbox 和一个Button 如下代码. <Window x:Class="WpKeyboard.MainWindow" xmlns="http://schemas.micr