Прокрутка нескольких виртуальных элементов управления - PullRequest
0 голосов
/ 15 ноября 2018

У меня есть элемент управления в виде календаря со столбцом для каждого дня недели и семью ObservableCollections, которые могут содержать до ста или более элементов каждый.

Я бы хотел иметь возможность вертикально прокручивать их [Редактировать] одновременно [/ Редактировать] при их виртуализации.

Прямо сейчас у меня есть следующий макет

<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 ]

0 голосов
/ 16 ноября 2018

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

Редактировать: Стоит также упомянуть, что для получения "плавной прокрутки" (ну, "гладкой", какой может получить wpf ..),необходимо установить для VirtualizingPanel.ScrollUnit значение «Pixel».Но он только работает, когда установлен для ItemsControl, , а не для самого ScrollViewer, ItemsPresenter или VirtualizingStackPanel.По какой-то причине.

0 голосов
/ 15 ноября 2018

Для виртуализации 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, в котором уже есть все необходимое для виртуализации вашего списка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...