Wirtualizacja ItemsControl?

Mam ItemsControl zawierający listę danych, które chciałbym zwirtualizować, jednak VirtualizingStackPanel.IsVirtualizing="True" nie wydaje się działać z ItemsControl.

Czy tak naprawdę jest, czy jest inny sposób na zrobienie tego, o czym Nie wiem?

Do testowania używam poniższego bloku kodu:

<ItemsControl ItemsSource="{Binding Path=AccountViews.Tables[0]}"
              VirtualizingStackPanel.IsVirtualizing="True">
<ItemsControl.ItemTemplate>
    <DataTemplate>
        <TextBlock Initialized="TextBlock_Initialized"  
                   Margin="5,50,5,50" Text="{Binding Path=Name}" />
    </DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Jeśli zmienię {[1] } na ListBox, widzę, że zdarzenie Initialized działa tylko kilka razy( ogromne marginesy są po prostu więc muszę przejść przez kilka rekordów), jednak jako {[1] } każdy element zostaje zainicjalizowany.

Próbowałem ustawić ItemsControlPanelTemplate na VirtualizingStackPanel, ale to chyba nie pomaga.

Author: Rachel, 2010-05-06

3 answers

W rzeczywistości jest o wiele więcej niż tylko użycie ItemsPanelTemplate VirtualizingStackPanel. Domyślnie ControlTemplate dla ItemsControl nie ma ScrollViewer, który jest kluczem do wirtualizacji. Dodanie do domyślnego szablonu kontrolnego dla ItemsControl (używając szablonu kontrolnego dla ListBox jako szablonu) daje nam następujące:

<ItemsControl
    VirtualizingStackPanel.IsVirtualizing="True"
    ScrollViewer.CanContentScroll="True"
    ItemsSource="{Binding Path=AccountViews.Tables[0]}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock
                Initialized="TextBlock_Initialized"
                Text="{Binding Path=Name}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <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>

(BTW, świetnym narzędziem do przeglądania domyślnych szablonów sterowania jest Show Me the Template )

Rzeczy do zauważenia:

Musisz ustawić ScrollViewer.CanContentScroll="True", Zobacz tutaj Po co.

Zauważ również, że ja umieściłem VirtualizingStackPanel.VirtualizationMode="Recycling". Zmniejszy to liczbę wywołań TextBlock_Initialized do tego, ile blokad tekstowych jest widocznych na ekranie. Więcej informacji na temat wirtualizacji interfejsu znajdziesz tutaj .

EDIT: zapomniałem podać oczywiste: jako alternatywne rozwiązanie możesz zastąpić ItemsControl przez ListBox :) Sprawdź również ten Optymalizacja wydajności na stronie MSDN i zauważ, że ItemsControl nie znajduje się w " kontrolkach implementujących wydajność Tabele funkcji", dlatego musimy edytować szablon kontrolki.

 186
Author: DavidN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-17 08:27:38

Bazując na odpowiedzi Davidna, oto styl, którego możesz użyć na ItemsControl, aby go wirtualizować:

<!--Virtualised ItemsControl-->
<Style x:Key="ItemsControlVirtualizedStyle" TargetType="ItemsControl">
    <Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
    <Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ItemsControl">
                <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>
        </Setter.Value>
    </Setter>
</Style>

Nie podoba mi się sugestia użycia Listboxa, ponieważ pozwalają one na wybór wierszy, w których niekoniecznie chcesz.

 24
Author: Zodman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-27 15:11:35

Po prostu domyślne ItemsPanel nie jest VirtualizingStackPanel. Musisz to zmienić:

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>
 -3
Author: Abe Heidebrecht,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-06 20:15:16