提高StackPanel中巨大的ListBox的性能? [英] Improve performance for huge ListBox in StackPanel?
问题描述
我正在使用StackPanel垂直排列几个控件(例如,标题,子标题,列表框,分隔符,列表框等).
I am using a StackPanel to layout several controls vertically (ie, Title, sub titles, listbox, separator, listbox, etc).
StackPanel是ScrollViewer的子级,以确保其内容始终可滚动.
The StackPanel is a child of a ScrollViewer to ensure its content is always scrollable.
StackPanel中的一个控件是ListBox.
One of the controls in the StackPanel is a ListBox.
其ItemsSource是绑定到庞大集合的数据,并且使用复杂的DataTemplate实现每个项目.
Its ItemsSource is data bound to a huge collection, and a complex DataTemplate is used to realise each item.
不幸的是,我的性能真的很差(CPU/内存较高).
Unfortunately, I'm getting really poor performance (high cpu/memory) with it.
我尝试了
- 将列表框的ItemsPanel设置为VirtualizingStackPanel,然后
- 将其ControlTemplate重写为仅ItemsPresenter(删除ListBox的ScrollViewer).
但是表演没有差异.我猜想StackPanel在测量期间会为其内部子级提供无限的高度?
But there were no difference in performances. I'm guessing the StackPanel gives its internal children infinite height during measure?
当我用其他面板/布局(例如Grid,DockPanel)替换ScrollViewer和StackPanel时,性能显着提高,这使我相信瓶颈以及解决方案都在虚拟化中.
When I replaced the ScrollViewer and StackPanel with other panels/layouts (e.g, Grid, DockPanel) and the performance improves significantly, which leads me to believe the bottleneck, as well as solution, is in virtualization.
我有什么办法可以改善此视图的CPU/内存性能?
Is there any way for me to improve the cpu/memory performance of this view?
[更新1]
原始示例项目: http://s000.tinyupload.com/index.php? file_id = 29810707815310047536
[更新2]
我尝试过重新样式化/模板化TreeView/TreeViewItems以提出以下示例.仍然需要很长的时间来启动/相同的高内存使用率.但是,一旦加载,滚动感觉就会比原始样本响应得多.
I tried restyling/templating TreeView/TreeViewItems to come up with the following example. It still takes a long time to start/same,high memory usage. But once loaded, scrolling feels a lot more responsive than the original sample.
想知道是否还有其他方法可以进一步改善启动时间/内存使用情况?
Wonder if there's any other way to further improve the start up time/memory usage?
重新样式的TreeView项目: http://s000.tinyupload.com/index.php? file_id = 00117351345725628185
Restyled TreeView project: http://s000.tinyupload.com/index.php?file_id=00117351345725628185
[更新2]
pushpraj的解决方案就像一个魅力
pushpraj's solution works like a charm
- 原件:
- 启动时间:35秒,
- 内存:393MB
- 滚动:缓慢
- Original:
- Startup: 35s,
- Memory: 393MB
- Scrolling: Slow
- 启动时间:18秒,
- 内存377MB,
- 滚动:快速
- 启动:< 1s,
- 内存:20MB,
- 滚动:快速
推荐答案
您可能会限制巨大列表框的最大大小并启用
Virtualization
you may perhaps limit the maximum size of the huge list box and enable
Virtualization
例如
<ListBox MaxHeight="500" VirtualizingPanel.IsVirtualizing="true" VirtualizingPanel.VirtualizationMode="Recycling" />
这将使列表框仅加载一些项目,并使列表框上的滚动条在需要时滚动到其余项目.
this will enable the ListBox to load a few items only and will enable a scrollbar on listbox to scroll to rest of the items if needed.
同时将
VirtualizationMode
设置为Recycling
将有助于您重用复杂的数据模板,从而无需为每个项目重新创建它们.at the same time setting
VirtualizationMode
toRecycling
will help you to reuse the complex data templates thus eliminating the need of re creating them again for every item.编辑
这是基于您的示例的解决方案,我将
CompositeCollection
与Virtualization
结合使用以实现所需的效果.here is a solution based on your sample, I have used
CompositeCollection
withVirtualization
to achieve the desired.xaml
<Grid xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:l="clr-namespace:PerfTest"> <Grid.Resources> <DataTemplate DataType="{x:Type l:Permission}"> <StackPanel Orientation="Horizontal"> <CheckBox /> <TextBlock Text="{Binding Name}" /> <Button Content="+" /> <Button Content="-" /> <Button Content="..." /> </StackPanel> </DataTemplate> <CompositeCollection x:Key="data"> <!-- Content 1 --> <TextBlock Text="Title" FontSize="24" FontWeight="Thin" /> <!-- Content 2 --> <TextBlock Text="Subtitle" FontSize="16" FontWeight="Thin" /> <!-- Content 3 --> <CollectionContainer Collection="{Binding DataContext, Source={x:Reference listbox}}" /> <!-- Content 4 --> <TextBlock Text="User must scroll past the entire list box before seeing this" FontSize="16" FontWeight="Thin" Padding="5" TextWrapping="Wrap" Background="#99000000" Foreground="White" /> </CompositeCollection> </Grid.Resources> <ListBox x:Name="listbox" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{StaticResource data}" /> </Grid>
代码
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); var items = new ObservableCollection<Permission>(); foreach (var i in Enumerable.Range(0, 10000).Select(i => new Permission() { Name = "Permission " + i })) { items.Add(i); } DataContext = items; } } public class Permission { public string Name { get; set; } }
因为我们无法为字符串创建数据模板,所以我将字符串集合更改为
Permission
集合.我希望在您的真实项目中会有所相似.since we can not create data template for string so I changed the string collection to
Permission
collection. I hope in your real project it would be something similar.尝试一下,看看它是否接近您的需求.
give this a try and see if this is close to what you need.
注意:
Collection="{Binding DataContext, Source={x:Reference listbox}}"
这篇关于提高StackPanel中巨大的ListBox的性能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!