2010-05-06 7 views
103

Ich habe eine ItemsControl enthält eine Liste von Daten, die ich virtualisieren möchte, aber VirtualizingStackPanel.IsVirtualizing="True" scheint nicht mit einer ItemsControl zu arbeiten.Virtualisierung eines ItemsControl?

Ist das wirklich der Fall oder gibt es eine andere Möglichkeit, dies zu tun, was mir nicht bewusst ist?

Um zu testen, ich den folgenden Codeblock verwendet haben:

<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 die ItemsControl zu einem ListBox ändern, ich, dass das Initialized Ereignis nur ein paar Mal läuft (die großen Margen zu sehen sind nur damit ich ein paar Datensätze durchgehen muss), aber als ItemsControl wird jedes Element initialisiert.

Ich habe versucht, die ItemsControlPanelTemplate auf VirtualizingStackPanel zu setzen, aber das scheint nicht zu helfen.

Antwort

178

ist es eigentlich viel mehr zu bieten, als nur die ItemsPanelTemplate Verwendung VirtualizingStackPanel. Der Standardwert ControlTemplate für ItemsControl hat keine ScrollViewer, die der Schlüssel zur Virtualisierung ist. Zusätzlich zu der die Standard-Steuerelementvorlage für ItemsControl (unter Verwendung der Steuervorlage für ListBox als Vorlage) gibt uns die folgenden:

<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, ein großes Werkzeug für das Betrachten Standard-Steuerungsschablonen ist Show Me The Template)

Was zu bemerken ist:

Sie müssen ScrollViewer.CanContentScroll="True" setzen, siehe here warum.

Beachten Sie auch, dass ich VirtualizingStackPanel.VirtualizationMode="Recycling" setzen. Dies wird die Anzahl der Male reduzieren, die TextBlock_Initialized aufgerufen wird, obwohl viele TextBlocks auf dem Bildschirm sichtbar sind. Sie können mehr über die UI-Virtualisierung here lesen.

EDIT: Vergessen, das Offensichtliche zu sagen: als eine alternative Lösung, können Sie einfach ersetzen ItemsControl mit ListBox :) Überprüfen Sie auch diese Optimizing Performance on MSDN page und feststellen, dass ItemsControl ist nicht in den „Steuerelemente, die Leistungsmerkmale Implement“ -Tabelle Deshalb müssen wir die Kontrollschablone bearbeiten.

+1

Danke, das ist genau die Art von was ich gesucht habe!Ich war auf der Suche nach einer anderen Art von Auswahlverhalten als eine Listbox und zu der Zeit dachte ich, es wäre am einfachsten, mit einem Element Kontrolle zu tun. – Rachel

+0

ListView funktioniert auch dafür. –

+0

Wenn diese Items Control weiter geschachtelt ist, sollten Sie auch eine Höhe geben. Ansonsten wird der Scrollviewer nicht angezeigt. – buckley

-3

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

<ItemsControl> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <VirtualizingStackPanel /> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 
+0

Danke, aber ich habe das schon versucht und es hat nicht funktioniert. – Rachel

+6

Ich stimme ab, da die Lösung unvollständig ist. Sie müssen einen Scrollviewer in der Vorlage verwenden, um die Virtualisierung zu aktivieren. –

22

Aufbauend auf DavidN Antwort, hier ist ein Stil, den Sie auf einem Item es virtualisieren verwenden:

<!--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 nicht den Vorschlag, eine List-Box zu verwenden, da sie die Auswahl von Zeilen ermöglichen, wo Sie tun Ich will es nicht unbedingt.