wpf virtualization itemscontrol virtualizingstackpanel

wpf - ¿Virtualizando un ItemsControl?



virtualization virtualizingstackpanel (3)

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

¿Es este realmente el caso o hay otra forma de hacer esto de la que no tengo conocimiento?

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 ItemsControl a un ListBox , puedo ver que el evento Initialized solo se ejecuta un puñado de veces (los enormes márgenes son solo para que solo tenga que pasar por algunos registros), sin embargo, como ItemsControl cada elemento se inicializa.

He intentado establecer ItemsControlPanelTemplate en VirtualizingStackPanel pero eso no parece ser de ayuda.


En realidad, hay mucho más que hacer que ItemsPanelTemplate use VirtualizingStackPanel . El ControlTemplate predeterminado para ItemsControl no tiene un ScrollViewer , que es la clave para la virtualización. Agregar a la plantilla de control predeterminada para ItemsControl (utilizando la plantilla de control para ListBox como plantilla) nos da lo 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 buscar plantillas de control predeterminadas es Muéstreme la plantilla )

Cosas para notar:

Tienes que configurar ScrollViewer.CanContentScroll="True" , mira here por qué.

También tenga en cuenta que pongo VirtualizingStackPanel.VirtualizationMode="Recycling" . Esto reducirá el número de veces que se llama a TextBlock_Initialized, sin embargo, muchos TextBlocks son visibles en la pantalla. Puede leer más sobre la virtualización de la interfaz de usuario here .

EDITAR: Olvidé indicar lo obvio: como solución alternativa, puede simplemente reemplazar ItemsControl con ListBox :). Además, consulte esta página Optimización del rendimiento en MSDN y observe que ItemsControl no se encuentra en la tabla "Controles que implementan características de rendimiento". por eso necesitamos editar la plantilla de control.


Es solo que el ItemsPanel predeterminado no es un VirtualizingStackPanel . Tienes que cambiarlo:

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


Sobre la base de la respuesta de DavidN, este es un estilo que puede usar en un ItemsControl para virtualizarlo:

<!--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 usar un ListBox ya que permiten la selección de filas donde no necesariamente lo desea.