企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
最近在帮同事调试一个类似资源管理器的wpf界面,左边TreeView去遍历大目录时UI卡死,刚开始我以为是在UI线程中调用系统API遍历目录的原因,就改为后台遍历,但是没有效果。 根本原因: TreeView的Style中Template对于ScrollViewer的CanContentScroll设置为FALSE, 导致VirtualizingStackPanel的虚拟化失效 解决办法: 设置ScrollViewer的CanContentScroll为True, 如: <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TreeView}"> <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true"> <ScrollViewer x:Name="_tv_scrollviewer_" Background="{TemplateBinding Background}" CanContentScroll="false" Focusable="false" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"> <ItemsPresenter/> </ScrollViewer> </Border> <ControlTemplate.Triggers> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/> </Trigger> <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true"> <Setter Property="CanContentScroll" TargetName="_tv_scrollviewer_" Value="true"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> <Style.Triggers> <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true"> <Setter Property="ItemsPanel"> <Setter.Value> <ItemsPanelTemplate> <VirtualizingStackPanel/> </ItemsPanelTemplate> </Setter.Value> </Setter> </Trigger> </Style.Triggers> 背景知识: 1. CanContentScroll主要用为控制当前itemsControl的滚动方式:逻辑滚动(True)和物理滚动(False)。 所谓逻辑滚动,就是点击滚动条每次最小单位为itemsControl中的每个Item的高度或者宽度。 而物理滚动,就是点击滚动条每次以物理像素(pixel)进行滚动。 2.一般我们在用ItemsControl时都会设置ItemsPanel为VirtualizingStackPanel或者类似虚拟化容器,并且把虚拟化标记IsVirtualizing打开, 但是有几种情况会导致界面上的虚拟化被禁止: - 项容器直接添加到 ItemsControl。 例如,如果应用程序将 ListBoxItem 对象显式添加到 ListBox,则 ListBox 不会虚拟化 ListBoxItem 对象。 - ItemsControl 中的项容器属于不同类型。 例如,使用 Separator 对象的 Menu 无法实现项回收,因为 Menu 包含 Separator 和 MenuItem 类型的对象。 - 将 CanContentScroll 设置为 false。 - 将 IsVirtualizing 设置为 false。