我有一个 ListBox,里面有一个水平 WrapPanel 来创建一个内容网格。它产生了正确的布局,但是超过一百个左右的项目真的很慢。
我在谷歌上看到了一些虚拟化 WrapPanel 的半生不熟的尝试,但它们似乎都没有准备好生产。
我错过了一个技巧吗?如何获得高性能和灵活(需要在调整大小时重排)面板布局?
(注意:单元格是固定大小的)。
我有一个 ListBox,里面有一个水平 WrapPanel 来创建一个内容网格。它产生了正确的布局,但是超过一百个左右的项目真的很慢。
我在谷歌上看到了一些虚拟化 WrapPanel 的半生不熟的尝试,但它们似乎都没有准备好生产。
我错过了一个技巧吗?如何获得高性能和灵活(需要在调整大小时重排)面板布局?
(注意:单元格是固定大小的)。
是的,虚拟化是正确的步骤。WPF 不能一次处理大量的 UI 项。编写自己的 VirtualizingWrapPanel 需要大量的 WPF 经验。WPF 没有“现成的”解决方案,因此您要么必须编写它,要么使用其他人的工作。
与提供与 StackPanel 相同功能的 VirtualizingStackPanel 不同,这并不完全像 WPF 附带的默认 WrapPanel 那样,有一些原因:
1- WrapPanels 可以在两个方向上增长,而 StackPanels 只能垂直或水平增长。此外,与面板方向正交的方向上的增长取决于面板方向方向上项目的大小,因此除非最后一行上所有项目的大小,否则不可能换行/列/列是已知的,但是如果正在虚拟化面板的两个方向,则这是不可能的(因为它会进行基于非像素的测量以提高性能)。
2-范围的大小与行/列(节)的数量相同。在 StackPanel 上这不是问题:由于每个部分只允许一个项目,因此范围宽度/高度是项目数。在 WrapPanel 上,section 的数量很大程度上取决于 item 的大小,并且由于 item 的大小不是固定的,可以在任何方向变化,因此无法计算 WrapPanel 上的 section 数量。
开发此面板时采用了以下解决方案:
1- 小组的范围永远无法确定。相反,在每个 MeasureOverride 之后,使用以下表达式估计节数:“numberofitems/averageitemspersection”。由于每个部分的平均项目数在每次滚动后都会更新,因此面板的范围是动态的。如果面板方向中的项目大小是固定的,则范围将是静态的。
2- items section/sectionindex 只能按顺序计算,因此如果您正在查看第一个项目并且您跳转到绕过一个或多个未实现部分的部分,面板将使用估计来知道哪个项目是第一个可见的,如果您返回已实现的部分并按顺序返回,这将得到纠正。例如:如果面板知道第 12 项在第 1 部分,并且面板估计每个部分有 10 个项目,(第 0 部分是第一个),如果您跳转到第 9 部分,面板将显示第 100 个项目作为第一个可见项目(只有从第 1 节到第 9 节,每节正好有 10 个项目,这才是正确的)。但是如果你回到第 1 部分并按顺序访问所有部分,直到到达第 9 部分,
3- 通常,滚动查看器内的 WrapPanel 可以垂直和水平滚动,但由于我只能虚拟化一个方向,因此此 wrappanel 只会在与面板方向正交的方向上滚动。(这意味着您不应该设置虚拟化面板高度/宽度明确)。
复制自;http://virtualwrappanel.codeplex.com/
我不明白您所说的固定单元是什么意思,但是如果每个项目的宽度/高度是固定的,那么您可以编写比我提供的虚拟化更好的虚拟化(VirtualWrapPanel)。只需浏览代码并尝试了解发生了什么。
您所说的“不太有效”可能是因为不可能制作出与一个 WrapPanel 完全相同的良好 VirtualizingWrapPanel(因为具体的项目行取决于下一个项目等等。),但如果你结合每个项目具有相同宽度/高度的事实,我相信你可以做得更好。
此外,您可以根据这些文章编写自己的解决方案来开始;
一:http: //blogs.msdn.com/dancre/archive/2006/02/06/implementing-a-virtualized-panel-in-wpf-avalon.aspx
二:http: //blogs.msdn.com/dancre/archive/2006/02/13/531550.aspx
三:http: //blogs.msdn.com/dancre/archive/2006/02/14/532333.aspx
四:http: //blogs.msdn.com/dancre/archive/2006/02/16/implementing-a-virtualizingpanel-part-4-the-goods.aspx
如何尝试使用 Grid 并将项目添加到 Grid 中,例如:
(但我没有测试它的性能)
public void InitializeGridAsFourColumns()
{
for (int i = 0; i < 4; i++)
{
_customGrid.ColumnDefinitions.Add(new ColumnDefinition());
}
}
private static int row = -1;
private static int column = 0;
public void AddItem(item)
{
//Add new RowDefinition every 4 items
if (column % 4 == 0)
{
RowDefinition rd = new RowDefinition();
rd.Height = GridLength.Auto;
_customGrid.RowDefinitions.Add(rd);
row++;
}
item.SetValue(Grid.RowProperty, row);
item.SetValue(Grid.ColumnProperty, column % 4);
column++;
_customGrid.Children.Add(item);
}