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!它现在虚拟化了,它变大了,宇宙的平衡已经恢复,我再也不想打独角兽了。在此之后,我只是剥离了视觉状态,因为我们不需要任何类型的项目选择,仅此而已,感谢大家的洞察力!很抱歉,我今天没能赏金