Domanda

Ho un ItemsControl contenente un elenco di dati che vorrei virtualizzare, tuttavia VirtualizingStackPanel.IsVirtualizing="True" non sembra funzionare con un ItemsControl.

E 'davvero questo il caso o c'è un altro modo di fare questo che io non sono a conoscenza?

Per testare Sono stato con il seguente blocco di codice:

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

Se cambio la ItemsControl ad un ListBox, posso vedere che l'evento Initialized viene eseguito solo una manciata di volte (gli enormi margini sono così ho solo passare attraverso alcuni record), ma come un ItemsControl ogni elemento diventa inizializzato.

Ho provato a fissare il ItemsControlPanelTemplate ad un VirtualizingStackPanel ma che non sembrano aiutare.

È stato utile?

Soluzione

In realtà c'è molto di più ad esso non solo rendendo l'uso ItemsPanelTemplate VirtualizingStackPanel. Il ControlTemplate predefinito per ItemsControl non dispone di un ScrollViewer, che è la chiave per la virtualizzazione. L'aggiunta al modello di controllo di default per ItemsControl (utilizzando il modello di controllo per ListBox come modello) ci dà la seguente:

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

(a proposito, un grande strumento per guardare modelli di controllo di default è Show Me The Template )

cose da notare:

Devi ScrollViewer.CanContentScroll="True" set, vedi qui per il motivo.

Si noti inoltre che ho messo VirtualizingStackPanel.VirtualizationMode="Recycling". Ciò consentirà di ridurre il numero di volte TextBlock_Initialized è chiamata a tuttavia molte TextBlocks sono visibili sullo schermo. Si può leggere di più sulla virtualizzazione UI qui .

EDIT: Ho dimenticato di affermare l'ovvio: come una soluzione alternativa, si può semplicemente sostituire ItemsControl con ListBox :) Inoltre, controllare questo Ottimizzare le prestazioni a pagina MSDN e notare che ItemsControl non è nei "controlli che implementano delle prestazioni caratteristiche" da tavolo, che è il motivo per cui abbiamo bisogno di modificare il modello di controllo.

Altri suggerimenti

Sulla risposta di DavidN, ecco uno stile che si può utilizzare su un ItemsControl di virtualizzare è:

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

Non mi piace il suggerimento di utilizzare un ListBox in quanto consentono la selezione di righe in cui non necessariamente desidera.

E 'solo che il ItemsPanel di default non è una VirtualizingStackPanel. È necessario cambiare:

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top