C# 大型可滚动数据SL4的虚拟化性能问题
问题:在可滚动区域显示大量数据会带来糟糕的性能和/或用户体验 尝试:基本上在列表框中设置一个数据模板,以显示填充数据的网格,其中虚拟化模式设置为回收,列表框上设置了固定高度。类似下面的例子C# 大型可滚动数据SL4的虚拟化性能问题,c#,silverlight,xaml,uiscrollview,datatemplate,C#,Silverlight,Xaml,Uiscrollview,Datatemplate,问题:在可滚动区域显示大量数据会带来糟糕的性能和/或用户体验 尝试:基本上在列表框中设置一个数据模板,以显示填充数据的网格,其中虚拟化模式设置为回收,列表框上设置了固定高度。类似下面的例子 <ListBox x:Name="Items" TabNavigation="Once" VirtualizingStackPanel.VirtualizationMode="Recycling" Height="500">
<ListBox x:Name="Items"
TabNavigation="Once"
VirtualizingStackPanel.VirtualizationMode="Recycling"
Height="500">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,5">
<HyperlinkButton Content="Action" Margin="5"/>
<ContentControl
cal:View.Model="{Binding}"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
ContentControl将从另一个视图引入一个标准的
,该视图将格式化由大约20个静态文本块和20个数据绑定文本块组成的填充项的总体布局
这工作正常,并将初始荷载减半。然而,现在的问题是,我需要的能力,高度不是一个固定的大小,所以它占用了它的父空间,甚至可以调整大小。多亏了@DanFox
,我发现你必须以一种或另一种形式固定高度才能调用虚拟化,否则RenderEngine就认为它有无限的空间
问题是:有没有更好的方法来实现这一点,或者我如何至少修复当前的技术以实现更好的用户体验?我可能会生成数百个这样的项目,因此我需要虚拟化的性能增强。但是,我还需要允许用户调整窗口大小并保持有效滚动的能力
非常感谢您的真知灼见,谢谢,节日快乐 按要求:-)到目前为止,我觉得我没有“回答”任何问题
你完全正确,应该有一种方法来获得高度动态。将其设置为固定高度只是为了确保虚拟化工作正常。使用性能分析器,或者使用SilverlightSpy,您有什么收获吗?我通过重构UI/VM上的绑定使其更高效,从而解决了其中一个问题。WinPhone7SL在这方面有一个很好的资源,有一个潜在的很好的解决方案,我会看看我是否能把它挖出来(理论应该转移到全脂SL)
根据您的VM体系结构,在缓存方面有一个很好的观点
可能很有用,因为它解释了更多的松散加载
以及WinPho 7开发团队的一份报告
希望这对你有所帮助如果只是因为固定的高度,你为什么不试试这个呢:
<Grid>
<ListBox x:Name="Items"
TabNavigation="Once"
VirtualizingStackPanel.VirtualizationMode="Recycling"
Height="{Binding Path=Height,RelativeSource={RelativeSource AncestorType=Grid}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,5">
<HyperlinkButton Content="Action" Margin="5"/>
<ContentControl
cal:View.Model="{Binding}"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
重要的是,要将列表框放入适合外部空间的容器中,而不是像stackpanel那样适合内部空间
试试这个,告诉我是否有用。:) 我认为,如果你神奇地将UI控件引入到你的数据模板中,那么你就违背了虚拟化的目的。这些控件(网格)本身是否被重用?当{Binding}改变时会发生什么?有多少代码是在看起来像附加行为的情况下运行的?也许你所做的可以让它发挥作用。但是,如果您只是制作一个直接的datatemplate(或者在其中放入一个普通的UserControl),您将知道其中的所有控件都将被重用,并且在切换它们的datacontext时将受到最小的惩罚 我不确定身高的问题。它应该可以工作(在Arrange中获得一个有限的高度),但这取决于它在引擎盖下做什么(也许它试图在Arrange提供高度之前解决所有问题)
您始终可以创建自己的虚拟化项控件。从面板派生,将其放入ScrollViewer中,并在面板上实现IScrollInfo。然后你就会知道事情是这样的所有原因:)我不确定这对于你的用例来说是否是一个可接受的解决方案,但是我已经创建了一个名为
delayedlayoututdupdatecontainer
的ContentControl,它包装了一个复杂的布局并有助于提高性能。DelayedLayoutUpdateContainer背后的思想是,只有在给定的时间跨度内未调整内容大小时,它才调整内容的大小。ControlTemplate中ContentPresenter的大小设置为绝对值。因此,这可能与将列表框高度设置为绝对值具有相同的效果。好的,下面是我最后所做的,必须说这是一个巨大的改进!我们以77秒的加载时间开始这件作品。通过对如何在背面绑定进行一些重构,我们缩短了大约20秒,因此问题仍然存在于UI呈现中。下面的答案显然比我最初想象的要简单,现在我们在15-20秒内加载了大量的数据(当然是虚拟化),更小的加载基本上是即时的,让我们回到正轨
这就是我所做的
<!-- This needs to be contained in a parent panel like a grid -->
<ListBox x:Name="Items" >
<ListBox.Template>
<ControlTemplate> <!-- Broke it out to allow resizing -->
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ItemsPresenter/> <!-- This little fella does magical things -->
</ScrollViewer>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel VirtualizingStackPanel.VirtualizationMode="Recycling"/> <!-- Recycle was a must -->
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<HyperlinkButton VerticalAlignment="Top" Margin="5" />
<!-- This guy I did need to set a minwidth on to retain nice and predictable scrolling
when datacontext was potentially changing -->
<ContentControl cal:View.Model="{Binding}" MinWidth="1160"
VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
就这样!瞧!所需要的只是打破控制模板并应用一个DirectItemsPresenter!它现在虚拟化了,它变大了,宇宙的平衡已经恢复,我再也不想打独角兽了。在此之后,我只是剥离了视觉状态,因为我们不需要任何类型的项目选择,仅此而已,感谢大家的洞察力!很抱歉,我今天没能赏金