滚动多个虚拟项控件

时间:2018-11-15 12:20:55

标签: c# wpf

我有一个类似于日历的控件,每个星期的每一天都有一列,并且有七个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]

2 个答案:

答案 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本身,不起作用。无论出于什么原因。