2012-10-11 94 views
1

我有一个ListBox和一个水平的WrapPanel里面来创建一个网格的内容。 它产生正确的布局,但它是真的缓慢与大于一百左右的项目。WPF流布局

我看到了一些在谷歌上虚拟化WrapPanel的尝试,但没有一个看起来已经准备好了。

我错过了一个招数? 如何获得性能和灵活性(需要重新调整大小)面板布局?

(注意:单元格的大小是固定的)。

回答

3

是的,虚拟化是正确的一步。 WPF不能处理大量的UI项目一次。 编写自己的VirtualizingWrapPanel需要在WPF中有很多经验。 WPF没有“准备就绪”的解决方案,所以你必须编写它,或者使用别人的工作。

不像VirtualizingStackPanel它提供的StackPanel的相同的功能,这并不能完全表现为随WPF默认WrapPanel,也有一些原因:

1 WrapPanels可以在两个方向发展,而StackPanels仅垂直或水平增长 。此外,与面板方向正交的方向 的增长取决于面板方向上的项目 的大小,因此不可能将 换行到新的行/列,除非所有项目的大小最后的 行/列是已知的,但是如果面板的两个方向被虚拟化(因为它基于非基于像素的 测量来提高性能),这是不可能的。

2-范围的大小与 行/列(节)的数量相同。在StackPanel上,这不是问题: 由于每个部分只允许有一个项目,因此区域宽度/高度为 项目的数量。在WrapPanel上,部分的数量高度取决于项目大小 ,并且由于项目的大小不是固定的并且可以在任何方向上改变,所以不可能计算 WrapPanel上的部分数量。

以下解决方案开发这一面板时获得通过:

1-面板的程度从来不知道是肯定的。相反,使用以下 表达式:'numberofitems/averageitemspersection',在每个MeasureOverride后估计 部分的数量。由于每个区段的平均每个区段的 数量在每次滚动后都会更新,因此面板的范围是动态的。如果面板方向上的项目尺寸 是固定的,则范围将是静态的。

2-项部/ sectionindex只能计算顺序, 因此,如果正在查看的第一项和跳转到一个节 绕过一个或多个未实现的部分,所述面板将使用 估计知道哪个项目是第一个可见的,如果你回到已实现的部分并按顺序返回 ,这将被更正为 。例如:如果小组知道第12项在 第1部分中,并且小组估计每个部分10项(第0项是 第一项),如果您跳转到第9项,小组将显示第100个 项作为第一项可见项目(仅当从 第1节到第9节,每节只有10个项目时才是正确的)。但是如果你去 回到第1节和顺序访问所有的部分,直至达到 第9,那么面板将所有项目的部分 正确因此没有进一步估计会由存储部分10

3 - 通常情况下,滚动查看器中的WrapPanel将被允许垂直和水平滚动,但由于我只能虚拟化一个方向的 ,因此此包装器只会在与面板方向正交的方向上滚动 (含义您不应该设置 虚拟化面板高度/宽度明确)。

复制自; http://virtualwrappanel.codeplex.com/

我不明白你的固定细胞的意思,但如果你有固定的每件宽度/高度,你可以写比我提供的一个(VirtualWrapPanel)更好的虚拟化。只需浏览代码并尝试了解发生了什么。

您称之为“不太合适”的原因可能是因为无法制作完美的VirtualizingWrapPanel,其工作方式与一个WrapPanel完全相同(因为特定的一行物品取决于接下来的物品等等)。 ,但如果将它与每个项目具有相同宽度/高度的事实相结合,我相信你可以做得更好。

此外,您可以根据这些文章编写自己的解决方案开始;

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

+0

我很害怕这个。 – NetworkBurger

+0

我接受这是正确的答案,因为它似乎是唯一的选择。 – NetworkBurger

0

如何尝试使用电网和项目添加到网格,如:

(但我没有测试其性能)

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

    }