2008-10-08 7 views
12

Me encontré con un problema al desarrollar una aplicación de visor de fotos. Uso ListBox para mostrar imágenes, que está contenido en un ObservableCollection. Adjunto ItemsSource de ListBox a ObservableCollection.En un ListBox de WPF con más de 1000 elementos de imagen, las imágenes de zoom se vuelven lentas

<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 obligar a la Image'height en ListBox con un control deslizante. (El valor del deslizador también se unen a zoombarmanager.ZoomBarWidth.Width). Pero encontré 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 anterior, tengo que usar ScrollViewer fuera de cuadro de lista, de lo contrario no tengo idea de cómo conseguir un scrollerbar desplazamiento suave y el WrapPanel parece tener sin barra de desplazamiento predeterminada. ¿Alguien ayuda? Se dice que el cuadro de lista con scrollviewer tiene un bajo rendimiento.

+0

Binding altura de cada imagen/anchura es terriblemente ineficiente, sólo tiene que utilizar un LayoutTransform en el ItemsPanel (respuesta agregado a este efecto) . – user7116

Respuesta

6

¡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 propia virtualizado WrapPanel ... Leer más here

también leer más acerca de otros temas como la implementación IScrollInfo here

También recomiendo encarecidamente que su no crear una nueva plantilla de control sólo 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 es necesario para envolver su cuadro de lista en un ScrollViewer!

[ACTUALIZACIÓN] Lea también this artículo de Josh Smith! Para hacer la envoltura WrapPanel ... también hay que recordar desactivar el desplazamiento horizontal ...

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

Estimado rudigrobler: ¿Ha probado esta aplicación y la ha abierto una carpeta que contiene 10000 imágenes? Lo intenté, y el rendimiento es terrible al cambiar el tamaño de la ventana principal. Creo que puede ser una buena solución para cientos de imágenes, pero para imágenes de mayor cantidad, listbox no puede manejarlo. – user25749

+0

Cambio la línea robotImages.Add en la muestra de Josh Smith en robotImages.Add (BitmapFrame.Create (uri) .Thumbnail); e hizo que el directorio contenga diez mil imágenes. Después de que se cargan las imágenes, el cambio de tamaño es tiempo de uso. – user25749

+0

El ejemplo se describe en http://www.codeproject.com/KB/WPF/CustomListBoxLayoutInWPF.aspx – user25749

3
  1. No estoy familiarizado con este componente, pero, en general, habrá limitaciones en el número 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 paginación, se agregan controles para cambiar entre bloques discretos de imágenes, por ejemplo, 100 a la vez, con las flechas de avance y retroceso, similar a la navegación registros de bases de datos.

Con la carga dinámica, implementa la paginación entre bastidores de 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 puede eliminar un lote de las anteriores para mantener el 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.

+0

Gracias, creo que este método funciona pero tal vez se necesita mucho trabajo. ¡Gracias! – user25749

0

¿Cómo es tu estilo 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.

+0

Lo agrego ahora, ¿tiene alguna idea de cómo mejorarlo? ¡Gracias! – user25749

1

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

utilizando un cuadro de lista con muchos elementos en un scrollviewer es otro problema de rendimiento conocido en 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.

1

Parte del problema es que está cargando la imagen completa en cada uno.Debe usar un IValueConverter para abrir cada imagen en un tamaño de miniatura estableciendo las propiedades DecodePixelWidth o DecodePixelHeight en el BitmapImage. He aquí un ejemplo que utilizo 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(); 
    } 

} 
2

le recomiendo que no enlaza la propiedad anchura/altura de cada imagen individual, sino que se enlaza un LayoutTransform en el cuadro de lista de 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> 
+0

Gracias sixlettervariables, ¡creo que tus palabras tienen sentido! ¡Voy a intentarlo! – user25749

+0

Encontré que todavía es muy lento. – user25749

+0

Combina las variables sixletter y la respuesta del rudigrobler, ¡el problema está resuelto! ¡Gracias! Cometí un error antes, ¡tu solución es la correcta! ¡Gracias! – user25749

Cuestiones relacionadas