Прокрутка нескольких виртуализированных элементов управления товарами

У меня есть календарный элемент управления со столбцом для каждого дня недели и семь 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 вертикально расширяться, а не виртуализировать вообще. Это так?

(Sidenote: я попытался удалить ScrollViewer и добавить CanVerticallyScroll = «True» в VirtualizingStackPanels и ожидал, что они будут прокручиваться независимо, чтобы проверить, лучше ли производительность, но они вообще не будут прокручиваться)

Каким может быть правильный макет для этого?

Изменить : отображение 100 элементов для каждого столбца (всего 700) занимает 13 секунд, прокрутка на самом деле в порядке

[Edit2] : Из-за требуемой одновременной прокрутки я попытался создать новую коллекцию, содержащую «одну строку» (7 элементов) и это как шаблон в списке. Ужасные результаты [/ Edit2]

Всего 2 ответа


Чтобы сделать виртуализацию ItemsControl, вам нужно не только использовать VirtualizingStackPanel, но также добавить ScrollViewer в шаблон элемента ItemsControl (обычно у 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>

В качестве другого решения вы можете, естественно, заменить свой ItemsControl на ListBox, у которого уже есть все необходимое для виртуализации вашего списка.


Решение проблемы состояло в том, чтобы не отображать семь столбцов каждый с одним виртуализированным элементом ItemsControl в ScrollViewer (который, казалось, расширил 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>

Что действительно важно здесь, это установить CanContentScroll-Свойство ScrollViewer в true или иначе виртуализация не будет работать (кто знает почему). Это отсутствовало в ответе @ Marc.

Edit: То, что также стоит упомянуть, заключается в том, что для получения «гладкой прокрутки» (ну, как «гладкая», как может получить wpf ..), нужно установить VirtualizingPanel.ScrollUnit в «Pixel». Но он работает только при установке в ItemsControl, а не в ScrollViewer, ItemsPresenter или VirtualizationStackPanel. Для любой причины.


Есть идеи?

10000