wpf image listbox performance

En un ListBox de WPF con más de 1000 elementos de imagen, las imágenes de zoom se vuelven lentas



performance (6)

Encontré un problema al desarrollar una aplicación de visor de fotos. Yo uso ListBox para Mostrar Imágenes, que está contenido en un ObservableCollection. Ato el ItemSource de ListBox a ObservableCollection.

<DataTemplate DataType="{x:Type modeldata:ImageInfo}"> <Image Margin="6" Source="{Binding Thumbnail}" Width="{Binding ZoomBarWidth.Width, Source={StaticResource zoombarmanager}}" Height="{Binding ZoomBarWidth.Width, Source={StaticResource zoombarmanager}}"/> </DataTemplate> <Grid DataContext="{StaticResource imageinfolder}"> <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled"> <ListBox Name="PhotosListBox" IsSynchronizedWithCurrentItem="True" Style="{StaticResource PhotoListBoxStyle}" Margin="5" SelectionMode="Extended" ItemsSource="{Binding}" /> </ScrollViewer>

También ato la Image''height en ListBox con un control deslizante. (El valor del control deslizante también se une a zoombarmanager.ZoomBarWidth.Width). Pero descubrí que si la colección se vuelve más grande, como: contiene más de 1000 imágenes, si uso el control deslizante para cambiar el tamaño de iamges, se vuelve un poco lento. Mi pregunta es. 1. ¿Por qué se vuelve lento? se convierte en que intenta hacer zoom en cada imagen, o simplemente porque se invoca notify ("Ancho") más de 1000 veces. 2. ¿Hay algún método para resolver este tipo de problema y hacerlo más rápido?

El PhotoListBoxStyle es así:

<Style~~ TargetType="{x:Type ListBox}" x:Key="PhotoListBoxStyle"> <Setter Property="Foreground" Value="White" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBox}" > <WrapPanel Margin="5" IsItemsHost="True" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Stretch" /> </ControlTemplate> </Setter.Value> </Setter> </Style~~>

Pero si utilizo el estilo de arriba, tengo que usar ScrollViewer fuera de ListBox, de lo contrario no tengo idea de cómo obtener una barra deslizadora de desplazamiento suave y parece que el wrappanel no tiene una barra de desplazamiento predeterminada. ¿Alguien ayuda? Se dice que el cuadro de lista con scrollviewer tiene un bajo rendimiento.


  1. No estoy familiarizado con este componente, pero en general habrá limitaciones en la cantidad de elementos que un cuadro de lista puede mostrar a la vez.

  2. Un método para resolver este tipo de problema es mantener el número de imágenes cargadas en el control dentro del número que el control puede mostrar a niveles de rendimiento aceptables. Dos técnicas para hacer esto son paginación o carga dinámica.

En la paginación, agrega controles para alternar entre bloques discretos de imágenes, por ejemplo, 100 a la vez, con flechas hacia adelante y hacia atrás, similar a navegar los registros de la base de datos.

Con la carga dinámica, implementa la paginación entre bastidores de tal forma que cuando el usuario se desplaza hasta el final, la aplicación carga automáticamente en el siguiente lote de imágenes, e incluso elimina potencialmente un lote de las anteriores para mantener la capacidad de respuesta razonable. Puede haber una pequeña pausa a medida que esto ocurre y puede haber algo de trabajo involucrado para mantener el control en el punto de desplazamiento correcto, pero esto puede ser una compensación aceptable.


¿Cómo es tu estilo de PhotoListBoxStyle? Si está cambiando la ItemsPanelTemplate de ListBox, existe una buena posibilidad de que ListBox no utilice VirtualizingStackPanel como panel de lista subyacente. Los ListBox no virtualizados son mucho más lentos con muchos elementos.


Le recomendaría que no vincule la propiedad Anchura / Altura de cada imagen individual, sino que vincula un LayoutTransform en ListBox''s ItemsPanel . Algo como:

<ListBox.ItemsPanel> <ItemsPanelTemplate> <StackPanel> <StackPanel.LayoutTransform> <ScaleTransform ScaleX="{Binding Path=Value, ElementName=ZoomSlider}" ScaleY="{Binding Path=Value, ElementName=ZoomSlider}" /> </StackPanel.LayoutTransform> </StackPanel> </ItemsPanelTemplate> </ListBox.ItemsPanel>


Parte del problema es que está cargando la imagen completa en cada uno. IValueConverter usar un IValueConverter para abrir cada imagen en un tamaño de miniatura configurando las propiedades DecodePixelWidth o DecodePixelHeight en BitmapImage . Aquí hay un ejemplo que uso en uno de mis proyectos ...

class PathToThumbnailConverter : IValueConverter { public int DecodeWidth { get; set; } public PathToThumbnailConverter() { DecodeWidth = 200; } public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) { var path = value as string; if ( !string.IsNullOrEmpty( path ) ) { FileInfo info = new FileInfo( path ); if ( info.Exists && info.Length > 0 ) { BitmapImage bi = new BitmapImage(); bi.BeginInit(); bi.DecodePixelWidth = DecodeWidth; bi.CacheOption = BitmapCacheOption.OnLoad; bi.UriSource = new Uri( info.FullName ); bi.EndInit(); return bi; } } return null; } public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) { throw new NotImplementedException(); } }


intente virtualizar su stackpael con la propiedad adjunta VirtualizingStackPanel.IsVirtualizing = "True". esto debería aumentar el rendimiento.

El uso de un cuadro de lista con muchos elementos en un scrollviewer es otro problema de rendimiento conocido dentro de wpf. si puede, trate de deshacerse del scrollviewer.

si sus plantillas de elementos son algo complejas, debería considerar utilizar el Modo de virtualización de reciclaje. esto le dice a su listbox que reutilice los objetos existentes y que no los cree nuevos todo el tiempo.


¡El problema es que su nuevo Panel de diseño es el WrapPanel y no es compatible con la virtualización! Es posible crear su propio Virtualized WrapPanel ... Leer más aquí

Lea también más sobre otros problemas, como la implementación IScrollInfo aquí

También recomiendo encarecidamente que no cree una nueva plantilla de control solo para reemplazar el panel de diseño ... Más bien haga lo siguiente:

<ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel Orientation="Horizontal"/> </ItemsPanelTemplate> </ListBox.ItemsPanel>

¡La ventaja de hacer esto es que no necesita envolver su listbox en un scrollviewer!

[ ACTUALIZACIÓN ] ¡También lea este artículo de Josh Smith! Para hacer el ajuste WrapPanel ... también debes recordar deshabilitar el desplazamiento horizontal ...

<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />