列表类控件虚拟化

WPF列表控件提供的最重要的功能是UI虚拟化(WPF编程宝典说的)。所有的WPF列表控件(所有继承自ItemsControl的控件,包括ListBox、CombBox、ListView、TreeView、DataGrid)都支持UI虚拟化。

UI虚拟化的支持实际上没有被构建到ListBox或ItemsControl类。而是通过VirtualizingStackPanel容器,除了增加虚拟化的支持,改面板与StackPanel面板功能类似。

ListBox、ListView、DataGrid都自动使用VirtualizingStackPanel面板来布局它们的子元素,所以不需要采取任何额外的步骤。

TreeView也是使用的VirtualizingStackPanel面板,但是默认情况下关闭了该支持,可以通过配置 VirtualizingStackPanel.IsVirtualizing="True" 来启用。

CombBox使用的是StackPanel面板,如果需要支持虚拟化,就必须明确的通过提供新的ItemsPanelTemplate 来添加虚拟化支持。

有一些因素会破坏UI虚拟化支持

1、在ScrollViewer中放置列表控件,ScrollViewer为其子内容提供了一个无限虚拟空间,在这个虚拟空间内,列表控件可以完整尺寸渲染自身,显示所有子项。只要将列表控件放入不会试图限制其尺寸的容器中,就会发生这一问题。例如将ListBox放入StackPanel或者设置Height为Auto的Grid行中。

2、改变列表控件的模板并且没有使用ItemsPresenter。 ItemsPresenter 使用 ItemsPanelTemplate,该模板指定了 VirtualizingStackPanel面板。如果破坏了这种关系或自己改变了ItemsPanelTemplate,从而不使用VirtualizingStackPanel面板,将会失去虚拟化特性。

3、不使用数据绑定。如果通过编程填充列表,那么不会发生虚拟化。

VirtualizingStackPanel面板的一些属性设置

1、启用虚拟化,也就是前面说到的TreeView控件启用虚拟化的方式,配置 VirtualizingStackPanel.IsVirtualizing="True"

2、项容器再循环,可以通过配置 配置 VirtualizingStackPanel.IsVirtualizing="True" .VirtualizationMode="Recyling" 来重复使用子项。

3、缓存长度,通过 VirtualizingStackPanel.CacheLength 与 VirtualizingStackPanel.CacheLengthUnit 来指定缓存长度。

4、滚动单位,通过配置 VirtualizingStackPanel.ScrollUnit 来指定滚动单位,可以是像素Pixel或是子项Item。

可以通过延迟滚动来进一步提升性能,开启延迟滚动后,在滚动滑块时不会更新列表显示,只有当用户释放滚动滑块时才刷新。通过配置 ScrollViewer.IsDeferredScrollingEnabled = "True" 开启

VirtualizationTest.xaml

cs 复制代码
<Window x:Class="DataBinding.VirtualizationTest"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="FastAndSlowComboBox" Height="300" Width="300" Loaded="Window_Loaded">
	<Grid Margin="5">
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="Auto"></ColumnDefinition>
			<ColumnDefinition></ColumnDefinition>
		</Grid.ColumnDefinitions>
		<Grid.RowDefinitions>
			<RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
		</Grid.RowDefinitions>
		<TextBlock Grid.Row="0" VerticalAlignment="Center">ComboBox:</TextBlock>
        <ComboBox Name="lstFast" Grid.Row="0" Grid.Column="1" Margin="5" ItemsSource="{Binding Path=Datas}" 
                  VirtualizingStackPanel.ScrollUnit="Pixel" VirtualizingStackPanel.VirtualizationMode="Recycling" VirtualizingStackPanel.CacheLength="100">
			<ComboBox.ItemsPanel>
				<ItemsPanelTemplate>
					<VirtualizingStackPanel></VirtualizingStackPanel>
				</ItemsPanelTemplate>
			</ComboBox.ItemsPanel>
		</ComboBox>
        <TextBlock Grid.Row="1" VerticalAlignment="Center">ListBox:</TextBlock>
        <ListBox Name="virtualListBox" Grid.Row="1" Grid.Column="1" Margin="5" ItemsSource="{Binding Path=Datas}" 
                 VirtualizingStackPanel.ScrollUnit="Pixel" VirtualizingStackPanel.VirtualizationMode="Recycling" VirtualizingStackPanel.CacheLength="100"/>


        <TextBlock Grid.Row="2" VerticalAlignment="Center">TreeView:</TextBlock>
        <TreeView Name="virtualTreeView" Grid.Row="2" Grid.Column="1" Margin="5" ItemsSource="{Binding Path=Datas}" VirtualizingStackPanel.IsVirtualizing="True"
                  VirtualizingStackPanel.ScrollUnit="Pixel" VirtualizingStackPanel.VirtualizationMode="Recycling" VirtualizingStackPanel.CacheLength="100" VirtualizingStackPanel.CacheLengthUnit="Item"/>

    </Grid>
</Window>

VirtualizationTest.xaml.cs

cs 复制代码
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace DataBinding
{
    /// <summary>
    /// Interaction logic for VirtualizationTest.xaml
    /// </summary>
    public partial class VirtualizationTest : Window
    {
        public VirtualizationTest()
        {
            InitializeComponent();
            DataContext = this;
        }

        private void InitData()
        {
            for (int i = 0; i < 10000; i++)
            {
                Datas.Add(i.ToString());
            }
        }
        public ObservableCollection<string> Datas { get; set; } = new ObservableCollection<string>();

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            InitData();
        }
    }
}
相关推荐
会飞的大可8 小时前
Spring Cloud Alibaba全景:Nacos、Sentinel、Seata整合实战
sentinel·wpf
baivfhpwxf202313 小时前
DataGrid 中增加选择列 功能实现
ui·wpf
爱学习的小囧16 小时前
ESXi 8.0 升级 9.0 详细攻略:安全升级、避坑与排障全指南
服务器·网络·安全·虚拟化·esxi8.0
czhc114007566316 小时前
winform 330 跨线程 异步
wpf·线程·winform
想你依然心痛18 小时前
HarmonyOS 5.0教育行业解决方案:基于分布式能力的沉浸式智慧课堂系统
分布式·wpf·harmonyos
Maybe_ch19 小时前
深度解析 WPF 线程模型:告别 UI 卡死,掌握 Dispatcher 核心机制
ui·wpf
code bean19 小时前
【Halcon 】用 Halcon 实现涂抹:Region、仿射变换与 WPF 交互
wpf·交互·halcon
爱学习的小囧2 天前
部署VMware ESXi 8.0U3i或者是集成驱动版的时候,发现不了NVME B66主板,如何处理?详细教程来了
驱动开发·esxi·虚拟化·esxi9.0集成驱动
爱学习的小囧2 天前
VMware ESXi V7 无 vCenter 虚拟机磁盘缩减攻略:安全释放存储空间(不丢数据)
服务器·网络·windows·安全·esxi·虚拟化
白露与泡影2 天前
Spring Cloud进阶--分布式权限校验OAuth2
分布式·spring cloud·wpf