Pregunta

Tengo una ItemsControl que contiene una lista de datos que me gustaría para virtualizar, sin embargo VirtualizingStackPanel.IsVirtualizing="True" no parecen funcionar con un ItemsControl.

¿Es esto realmente así o hay otra manera de hacer esto que no soy consciente de?

Para probar He estado usando el siguiente bloque de código:

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

Si cambio la ItemsControl a un ListBox, puedo ver que el evento Initialized sólo se ejecuta un puñado de veces (los enormes márgenes son tan sólo tengo que pasar por unos pocos registros), sin embargo, como un ItemsControl cada artículo se inicializado.

He intentado fijar la ItemsControlPanelTemplate a un VirtualizingStackPanel pero eso no parece ayudar.

¿Fue útil?

Solución

En realidad hay mucho más a él que sólo hacer uso del ItemsPanelTemplate VirtualizingStackPanel. El ControlTemplate defecto para ItemsControl no tiene un ScrollViewer, que es la clave para la virtualización. Adición a la plantilla el control predeterminado para ItemsControl (usando la plantilla de control para ListBox como una plantilla), nos da la siguiente:

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

(Por cierto, una gran herramienta para analizar las plantillas de control por defecto es me muestra la plantilla )

cosas a destacar:

Usted tiene que fijar ScrollViewer.CanContentScroll="True", consulte aquí por qué.

También aviso que puso VirtualizingStackPanel.VirtualizationMode="Recycling". Esto reducirá el número de veces TextBlock_Initialized se llama a TextBlocks embargo muchos son visibles en la pantalla. Usted puede leer más en la interfaz de usuario de virtualización aquí .

EDIT: Se olvidó de decir lo obvio: como una solución alternativa, sólo puede sustituir con ItemsControl ListBox :) Además, echa un vistazo a este Optimización del rendimiento en la página de MSDN y el aviso de que ItemsControl no está en los "controles que implementan características de rendimiento" de mesa, por lo que tenemos que editar la plantilla de control.

Otros consejos

Sobre la base de la respuesta de DavidN, aquí es un estilo que puede utilizar en una ItemsControl para virtualizar él:

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

No me gusta la sugerencia de utilizar un cuadro de lista, ya que permiten la selección de filas en las que no necesariamente lo desee.

Es sólo que el ItemsPanel por defecto no es un VirtualizingStackPanel. Es necesario cambiarlo:

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top