问题:在可滚动区域中显示大量数据会导致性能和/或用户体验糟糕。
尝试:基本上在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个数据绑定TextBlock组成的已填充项目的整体布局。
这样可以正常工作,并将初始载荷减半。但是,现在的问题是我需要高度的能力不是一个固定的大小,所以它占用了其父级的可用空间,甚至可以调整大小。感谢@DanFox
我发现你必须以一种或另一种形式修复高度以调用虚拟化,或者RenderEngine只是认为它有无限的空间。
问题是:有没有更好的方法来做到这一点,或者我怎样才能至少修复当前的技术以实现更好的用户体验?我正在生成数百个这样的项目,所以我需要虚拟化的性能增强。但是,我还需要允许用户调整窗口大小并保持有效滚动的能力。
非常感谢任何见解,谢谢和节日快乐!
答案 0 :(得分:1)
按要求:-)我觉得我到目前为止没有“回答”任何事情......
你是绝对正确的,应该有一种让身高变得动态的方法。将其设置为固定高度是一个快速检查,只是为了确保虚拟化正常工作。您是否可以使用性能分析器,或者使用SilverlightSpy?我通过重构UI / VM上的绑定使其更有效率,使其中一个问题消失了。 WinPhone7 SL有一个很好的资源,有一个潜在的好解决方案,我会看看我是否可以把它挖出来(理论应该转移到全脂SL)
This在缓存方面有一个很好的观点,具体取决于您的VM架构
This可能有用,因为它解释了laxy加载更多
来自WinPho 7开发团队的couple of hints。
希望有所帮助
答案 1 :(得分: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!它现在虚拟化很好,它调整大小,平衡已经恢复到宇宙,我不再想要打一个独角兽。之后,我只是剥离了视觉状态,因为我们不需要任何项目选择,这就是它,感谢每个人的见解!对不起,我这次不能奖励。
答案 2 :(得分: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放入适合外部空间的容器中,而不是像堆栈面板那样适合内部空间。
试试这个并告诉我它是否有帮助。 :)
答案 3 :(得分:0)
我认为,如果你神奇地将UI控件纳入数据模板,那么你就无法实现虚拟化的目的。这些控件(网格)本身是否可以重复使用?当{Binding}改变时会发生什么?看起来像附加行为的代码运行了多少代码?也许你所做的事情可以做得很好。但是如果你只是制作一个直接的数据模板(或者将其放入一个普通的UserControl),你就会知道它中的所有控件都将被重用,并且在切换它们的datacontext时会有最小的惩罚。
我不确定Height的问题。它应该工作(在编排中得到一个有限的高度),但它取决于它在引擎盖下做了什么(也许它试图在安排使高度可用之前解决所有问题)。
您始终可以创建自己的虚拟化项目控件。从Panel派生,将其放入ScrollViewer,并在Panel上实现IScrollInfo。那么你就会知道事情就是这样的所有原因:)
答案 4 :(得分:0)
我不确定,如果这对您的用例来说是一个可接受的解决方案,但我创建了一个名为DelayedLayoutUpdateContainer
的ContentControl,它包含复杂的布局并有助于提高性能。 DelayedLayoutUpdateContainer背后的想法是,只有当它在给定的时间跨度内没有自己调整大小时,它才会调整其内容的大小。 ControlTemplate中ContentPresenter的大小设置为绝对值。因此,这可能与将ListBoxes高度设置为绝对值具有相同的效果。