12

问题:在可滚动区域中显示大量数据会带来糟糕的性能和/或用户体验。

尝试:基本上在 ListBox 中设置一个 DataTemplate 以显示填充数据的网格,其中 VirtualizationMode 设置为 Recycle 并在 ListBox 本身上设置了固定高度。类似于下面的示例。

 <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 将从另一个视图引入一个标准,该标准<Grid>格式化由大约 20 个静态和 20 个数据绑定 TextBlocks 组成的填充项目的整体布局。

这工作正常,并将初始负载减半。但是,现在的问题是我需要高度不是固定大小的能力,因此它占用了其父级中的可用空间,甚至可以调整大小。感谢@DanFox我发现您必须以一种或另一种形式修复高度才能调用虚拟化,否则 RenderEngine 只是认为它有无限的空间。

问题是:有没有更好的方法来做到这一点,或者我怎样才能至少修复当前的技术以实现更好的用户体验?我可能会生成数百个这样的项目,因此我需要虚拟化的性能增强。但是,我还需要允许用户调整窗口大小并保留有效滚动的能力。

非常感谢任何见解,谢谢,节日快乐!

4

5 回答 5

1

根据要求:-)到目前为止,我觉得我没有“回答”任何事情......

你是绝对正确的,应该有一种获得高度动态的方法。将其设置为固定高度是一种快速检查,以确保虚拟化正常工作。你有没有使用性能分析器,或者使用 SilverlightSpy?我通过重构 UI/VM 上的绑定以使其更高效,从而解决了这些问题之一。WinPhone7 SL 有一个很好的资源,有一个可能很好的解决方案,我会看看我能不能把它挖出来(理论应该转移到全脂 SL)

根据您的VM架构,这对缓存有好处

可能很有用,因为它解释了更多的松弛加载

以及来自 WinPho 7 开发团队的一些提示。

希望有帮助

于 2012-12-21T09:57:32.960 回答
1

好的,这就是我最终要做的事情,不得不说这是一个巨大的进步!我们从这个特定作品的 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>

就是这样!瞧!所要做的就是打破 ControlTemplate 并直接应用 ItemsPresenter!它现在虚拟化了,它调整了大小,宇宙恢复了平衡,我不再想打独角兽了。之后我只是剥离了视觉状态,因为我们不需要任何类型的项目选择,仅此而已,感谢大家的见解!抱歉,这次我不能奖励赏金。

于 2012-12-26T17:11:28.807 回答
0

如果它只是由于固定的高度,你为什么不试试这个:

<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>

重要的是,您将 ListBox 放入适合外部空间而不是像堆栈面板那样适合内部空间的容器中。

试试这个,告诉我它是否有帮助。:)

于 2012-12-21T10:40:18.987 回答
0

我认为,如果您神奇地将 UI 控件引入数据模板,那么您就违背了虚拟化的目的。这些控件(网格)本身是否被重用?当 {Binding} 改变时会发生什么?在看起来像附加行为的情况下运行了多少代码?也许你所做的可以变得高效。但是,如果您只是制作一个直接的数据模板(或在其中放入一个普通的 UserControl),您就会知道其中的所有控件都将被重用,并且在切换它们的数据上下文时损失最小。

我不确定身高的问题。它应该可以工作(在 Arrange 中获得有限的高度),但这取决于它在引擎盖下做了什么(也许它试图在 Arrange 使高度可用之前弄清楚所有事情)。

您始终可以创建自己的虚拟化项目控件。派生自Panel,放入一个ScrollViewer,在Panel上实现IScrollInfo。然后你就会知道为什么事情是这样的所有原因:)

于 2012-12-21T16:26:06.713 回答
0

我不确定这是否是您的用例可接受的解决方案,但我创建了一个名为 ContentControl 的名称DelayedLayoutUpdateContainer,它包含复杂的布局并有助于提高性能。DelayedLayoutUpdateContainer 背后的想法是,它仅在给定时间跨度内未自行调整大小时调整其内容的大小。ControlTemplate 中 ContentPresenter 的大小设置为绝对值。因此,这可能与将 ListBoxes 高度设置为绝对值具有相同的效果。

于 2012-12-21T17:01:58.610 回答