我有一个类似于日历的控件,每个星期的每一天都有一列,并且有七个ObservableCollections,每个可以包含多达一百个或更多项。
我希望能够在虚拟化它们的同时垂直滚动它们 [Edit] 。 [/ Edit] 。
现在我有以下布局
<ScrollViewer>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<!-- Monday -->
<Border Grid.Column="0">
<ItemsControl ItemsSource="{Binding Monday}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsVirtualizing="True" VirtualizationMode="Recycling" ... />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<MyControl Item="{Binding}" ... />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
...
</Grid>
</ScrollViewer>
但是,性能令人怀疑,我认为这是由于ScrollViewer允许Grid-> Border-> VirtualizingStackPanel垂直扩展而不进行虚拟化。是这样吗?
(旁注:我试图删除ScrollViewer并将CanVerticallyScroll =“ True”添加到VirtualizingStackPanels中,并希望它们独立滚动以检查性能是否更好,但它们根本不会滚动)
什么是正确的布局?
编辑:每列显示100个元素(共700个)需要13秒,滚动实际上是可以的
[Edit2] : 由于需要同时滚动,因此我尝试创建一个新集合,该集合包含“一行”(7个项目),并作为列表视图中的模板。糟糕的结果[/ Edit2]
答案 0 :(得分:0)
要使ItemsControl进行虚拟化,您不仅需要使用VirtualizingStackPanel,而且还需要向ItemsControl的模板中添加一个ScrollViewer(通常ItemsControl没有ScrollViewer)。
将此模板添加到ItemsControl中:
<ItemsControl.Template>
<ControlTemplate>
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
SnapsToDevicePixels="True">
<ScrollViewer Padding="{TemplateBinding Control.Padding}"
Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
作为另一种解决方案,您当然可以用ListBox替换ItemsControl,该ListBox已经具有虚拟化列表所需的一切。
答案 1 :(得分:0)
该问题的解决方案是不使用ScrollViewer中的一个虚拟化ItemsControl呈现七列,这似乎扩展了ItemsControls并使其绘制所有控件),而是使用一个ItemsControl呈现,从而解决了ItemsControl.Template中的滚动问题并一次显示一个行。
我创建了一个新集合,并“按行”抓取了对象
for(int PI = 0; PI < MathHelper.Max(Monday.Count, Tuesday.Count, Wednesday.Count, Thursday.Count, Friday.Count, Saturday.Count, Sunday.Count); PI++)
{
Presentation.Add(new WeekRow(
Monday.Count > PI ? Monday[PI] : null,
Tuesday.Count > PI ? Tuesday[PI] : null,
Wednesday.Count > PI ? Wednesday[PI] : null,
Thursday.Count > PI ? Thursday[PI] : null,
Friday.Count > PI ? Friday[PI] : null,
Saturday.Count > PI ? Saturday[PI] : null,
Sunday.Count > PI ? Sunday[PI] : null
));
}
并使用
显示它们<ItemsControl ItemsSource="{Binding Presentation}" VirtualizingPanel.ScrollUnit="Pixel">
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer CanContentScroll="True" Focusable="False">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel
Orientation="Vertical"
IsVirtualizing="True"
VirtualizationMode="Recycling">
</VirtualizingStackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<MyControl Item="{Binding Monday}" Grid.Column="0" ... />
...
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate
</ItemsControl>
这里真正重要的是将ScrollViewer的CanContentScroll-Property设置为true,否则虚拟化不起作用(谁知道为什么)。 @Marc的答案中没有此内容。
编辑:另外值得一提的是,要获得“平滑的滚动”效果(可以像wpf一样获得“平滑的滚动效果”),必须将VirtualizingPanel.ScrollUnit设置为“ Pixel” ”。但是,当设置为ItemsControl时,它仅在 中起作用;对于ScrollViewer,ItemsPresenter或VirtualizingStackPanel本身,不起作用。无论出于什么原因。