1

I'm loading a lot of images in a listbox. There was a sensible loading time before i tried to virtualize.

Now that i use virtualization only the elements that fall into view are loaded, exactly as i wanted; but they don't seem to unload once they fall outside the view so if i scroll all the way down to the bottom all the items are loaded and i lose the advantage of virtualizing.

Before i display any image, my app consumes 140MB, then i display 10 images and my memory usage equals 161MB, if i scroll to the last image the usage is 300MB. If 10 images use 21 MB, then with 300MB all the images must be loaded.

This behavior is furthermore confirmed by inspecting the number of loaded ListBoxItems with Snoop.

Nothing special in the code, i just make sure CanContentScroll is true to enable not disable virtualization. I customize the ItemContainerStyle and the template of the ListBox but it shouldn't affect the virtualization (or atleast not only the unloading part), isn't it?

<ListBox ItemsSource="{Binding myItems}"  CanContentScroll="True"/>

Am I missing something?

CONCLUSION

The virtualization obviously works. Each ItemContainer is unloaded at some point when they fall outside the view.

The problem is probably how the BitmapImage caches. In facts, i'm using the following DataTemplate to show the images:

 <Image>
     <Image.Source>
         <BitmapImage UriSource="{Binding}" />
     </Image.Source>
 </Image>
Mauro Sampietro
  • 2,739
  • 1
  • 24
  • 50
  • In ***"they don't seem to unload"***, the word "seem" suggests that you're perceiving something in some way, which you interpret to mean that they're not "unloading". Can you be more specific about that, and about what you mean by "unload"? Are you just talking about the `Unloaded` event? – 15ee8f99-57ff-4f92-890c-b56153 Jul 10 '17 at 15:05
  • 1
    `CanContentScroll` enables virtualisation ? What about ``? – XAMlMAX Jul 10 '17 at 15:06
  • 1
    @EdPlunkett Of course: before i display any image, my app consumes 140MB then i display 10 images and my memory usage equals 161MB, if i scroll to the last image the usage is 300MB. If 10 images use 21 MB, then with 300MB all the images must be loaded. – Mauro Sampietro Jul 10 '17 at 15:13
  • @sam Thanks. That would be a great addition to the question. – 15ee8f99-57ff-4f92-890c-b56153 Jul 10 '17 at 15:14
  • @XAMlMAX CanContetScroll=False disables virtualization, so it must set to true to take advantage of virtualization. Google it. The other properties are set by default as you explicitly write. – Mauro Sampietro Jul 10 '17 at 15:14
  • Ah, that is something I never knew, thanks. I always used the explicit definition, but I also had to explicitly define the panel for the list view for it to work. like : ` ` – XAMlMAX Jul 10 '17 at 15:17
  • @XAMlMAX the default ItemsPanel in a listbox is a VirtualizingStackPanel – Mauro Sampietro Jul 10 '17 at 15:20
  • 1
    @sam Except memory consumption, how do you detect that item containers are not unloaded? Did you attach an Unloaded event handler? – Clemens Jul 10 '17 at 15:39
  • @Clemens via Snoop i can see that ListBoxItems are always increasing in number. I'd expect a constant number of ListBoxItems. – Mauro Sampietro Jul 11 '17 at 07:05
  • Not sure how virtualization is supposed to determine when exactly an item container should be disposed of. You may still verify that this isn't just garbage collection coming late, by attaching an Unloaded handler. Also make sure that VirtualizationMode is not (for whatever reason) set to Recycling instead of Standard. – Clemens Jul 11 '17 at 07:08
  • @Clemens i'm not sure where to attach the unload handler. ItemsPresenter, the scrollviewer the listbox itself? Can you please link me to an example? – Mauro Sampietro Jul 11 '17 at 07:20
  • With an EventSetter in the ItemContainerStyle. – Clemens Jul 11 '17 at 07:20
  • @Clemens yes, the unloaded event is called while scrolling – Mauro Sampietro Jul 11 '17 at 08:01
  • @Clemens To show images i'm using a DataTemplate which set the source via a BitmapImage. may BitmapImage not be unloading it's cache? – Mauro Sampietro Jul 11 '17 at 08:10
  • That's quite possible. You may try to set BitmapCreateOption.IgnoreImageCache to avoid that. – Clemens Jul 11 '17 at 08:12

1 Answers1

2

What's going on here is a memory leak problem with BitmapImage and Stream. The problem is described here

The solution is to read the image through a WrappingStream as described and implemented here

Read the image like this and assign it to Image.Source:

  BitmapImage bitmap = new BitmapImage();

  using( var stream = new FileStream( uri, FileMode.Open ) )
  using( WrappingStream wrapper = new WrappingStream( stream ) )
  {
      bitmap.BeginInit();
      bitmap.CacheOption = BitmapCacheOption.OnLoad;
      bitmap.StreamSource = stream;
      bitmap.EndInit();
      bitmap.Freeze();
 }

  return bitmap;
Mauro Sampietro
  • 2,739
  • 1
  • 24
  • 50