Virtualisierung eines ItemsControl?

125

Ich habe ItemsControleine Liste mit Daten, die ich virtualisieren möchte, VirtualizingStackPanel.IsVirtualizing="True"scheint jedoch nicht mit einem zu funktionieren ItemsControl.

Ist das wirklich der Fall oder gibt es einen anderen Weg, den ich nicht kenne?

Zum Testen habe ich den folgenden Codeblock verwendet:

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

Wenn ich das ItemsControlin a ändere ListBox, kann ich sehen, dass das InitializedEreignis nur einige Male ausgeführt wird (die riesigen Ränder sind nur so, dass ich nur einige Datensätze durchgehen muss), jedoch wird ItemsControljedes Element initialisiert.

Ich habe versucht, das ItemsControlPanelTemplateauf a zu setzen, VirtualizingStackPanelaber das scheint nicht zu helfen.

Rachel
quelle

Antworten:

219

Es steckt tatsächlich viel mehr dahinter, als nur den ItemsPanelTemplateGebrauch zu machen VirtualizingStackPanel. Die Standardeinstellung ControlTemplatefür ItemsControlhat keine ScrollViewer, was der Schlüssel zur Virtualisierung ist. Durch Hinzufügen zur Standardsteuerungsvorlage für ItemsControl(Verwenden der Steuerungsvorlage ListBoxals Vorlage) erhalten wir Folgendes:

<ItemsControl ItemsSource="{Binding AccountViews.Tables[0]}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <TextBlock Initialized="TextBlock_Initialized"
                 Text="{Binding Name}" />
    </DataTemplate>
  </ItemsControl.ItemTemplate>

  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <VirtualizingStackPanel IsVirtualizing="True"
                              VirtualizationMode="Recycling" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>

  <ItemsControl.Template>
    <ControlTemplate TargetType="ItemsControl">
      <Border BorderThickness="{TemplateBinding BorderThickness}"
              BorderBrush="{TemplateBinding BorderBrush}"
              Background="{TemplateBinding Background}">
        <ScrollViewer CanContentScroll="True" 
                      Padding="{TemplateBinding Padding}"
                      Focusable="False">
          <ItemsPresenter />
        </ScrollViewer>
      </Border>
    </ControlTemplate>
  </ItemsControl.Template>
</ItemsControl>

(Übrigens ist Show Me The Template ein großartiges Tool zum Anzeigen von Standardsteuerungsvorlagen. )

Dinge zu beachten:

Sie müssen einstellen ScrollViewer.CanContentScroll="True", sehen Sie hier, warum.

Beachten Sie auch, dass ich setzen VirtualizingStackPanel.VirtualizationMode="Recycling". Dadurch wird die Anzahl der TextBlock_InitializedAufrufe reduziert, obwohl auf dem Bildschirm viele Textblöcke sichtbar sind. Weitere Informationen zur UI-Virtualisierung finden Sie hier .

EDIT: Vergessen , das Offensichtliche zu sagen: als eine alternative Lösung, können Sie einfach ersetzen ItemsControlmit ListBox:) Auch, ob diese Optimierung der Leistung auf MSDN - Seite und Hinweisen , die ItemsControlnicht in dem „Steuerelemente , die Leistung implementieren Funktionen“ Tabelle, weshalb Wir müssen die Kontrollvorlage bearbeiten.

DavidN
quelle
1
Danke, genau das habe ich gesucht! Ich suchte nach einer anderen Art von Auswahlverhalten als eine Listbox und dachte damals, es wäre am einfachsten, mit einem Elementsteuerelement zu arbeiten.
Rachel
Wenn diese Elementsteuerung weiter verschachtelt ist, sollten Sie ihr auch eine Höhe geben. Andernfalls wird der Scrollviewer nicht angezeigt.
Buckley
9
"Beachten Sie auch, dass ich VirtualizingStackPanel.VirtualizationMode = Recycling eingefügt habe". Soll es nicht in der von Ihnen bereitgestellten Probe sein?
Buckley
Hat Virtualisierung auch funktionieren , wenn Wrap ItemsControlin ScrollViewerinstread Zugabe Scrollzu ControlTemplate?
Demo
@DavidN Wo oder wie kann ich die Spaltenüberschriften in Ihre Lösung einfügen?
Ozkan
37

Aufbauend auf der Antwort von DavidN finden Sie hier einen Stil, den Sie für ein ItemsControl verwenden können, um es zu virtualisieren:

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

Ich mag den Vorschlag, eine ListBox zu verwenden, nicht, da sie die Auswahl von Zeilen ermöglicht, in denen Sie sie nicht unbedingt möchten.

Zodman
quelle
-3

Es ist nur so, dass der Standardwert ItemsPanelnicht a ist VirtualizingStackPanel. Sie müssen es ändern:

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>
Abe Heidebrecht
quelle
8
Ich stimme nicht ab, da die Lösung unvollständig ist. Sie müssen einen Scrollviewer in der Vorlage verwenden, um die Virtualisierung zu aktivieren.
Saraf Talukder