1

I'm trying to create a listbox that may contain over a thousand images in a grid like design. In term of design it would be quite similar to this:

https://i.stack.imgur.com/7URQD.jpg

Since I can't use a wrappanel as that would break UI virtualization and a stackpanel can't list images in such a grid(?), I'm trying to solve this issue using a modified version of https://virtualwrappanel.codeplex.com

My XAML:

<ListBox x:Name="GameWheel" ItemsSource="{Binding GameData}" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden">
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <c:VirtualizingWrapPanel IsItemsHost="True" />
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Image x:Name="GameImage" Source="{Binding Path=ImagePath}" Width="{Binding ElementName=GameWheel, Path=ActualWidth, Converter={StaticResource widthConverter}}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

While this approach works, it's still quite slow and buggy, especially when using bind on the image width. Is there a better way of archiving the same result? Without the custom wrappanel preferably.

NeoID
  • 901
  • 1
  • 11
  • 29
  • Are all items going to be the same Width (and height)? – Kcvin Aug 27 '15 at 20:34
  • I set the same width on all, but some might have a different height.... (I don't have control over the images itself). However, for now I limit the width so I always get 5 images on a row. – NeoID Aug 28 '15 at 05:35

1 Answers1

1

Check out my implementation of VirtualizingWrapPanel. Also available (with more included) from NuGet.

This code originally came from this CodeProject article which mostly worked and appears to be the same place you started. Along the way I fixed several bugs and improved performance so it might help you as well.

Update: The key is going to be to bind to the VirtualizingWrapPanel.ItemWidth rather than Image.Width. There was a bug in both implementations of the VirtualizingWrapPanel that would prevent the children from being resized if the ItemHeight or ItemWidth values changed. I fixed this bug in this commit (line 358).

Admittedly it's a brute force fix but I wanted to get something checked in for you and have to head out. I tested it with 10,000 images and it was very snappy. I'll work on a better solution (ie: only remeasure when we know the value has changed) and update this answer when I do.

Update 2: Quick change to improve the child.Measure with this commit.

//TODO: If either child Height or Width == PositiveInfinity and the other side == ChildSlotSize then we probably don't need to measure. Need to test this
if (!child.DesiredSize.Equals(ChildSlotSize))
{
    child.Measure(ChildSlotSize);
}

Still room for improvement but no time for proper testing right now and this works.

Cory Charlton
  • 8,868
  • 4
  • 48
  • 68
  • Thank you. I also based my version on that codeproject post. However, adding a width (binding it to the size of the screen) sadly adds 5-10 seconds before the WPF page containing this control is loaded. Settings a fixed width is way faster, but sadly doesn't scale with the size of the screen. – NeoID Aug 28 '15 at 05:52
  • @NeoID maybe try setting the binding on the `ItemWidth` property of the `VirtualizingWrapPanel` and setting the `Image` to fill the available space? – Cory Charlton Aug 28 '15 at 06:20
  • Tried that as well. Changed the `VirtualizingWrapPanel` to `` but then all images disappear. Setting a fixed width works. I guess something funny is going on width the binding, just not sure what as it works everywhere else in my code. It just divides the width on 5. – NeoID Aug 28 '15 at 07:08
  • @NeoID See my updated answer with bug fix and let me know if it helps. – Cory Charlton Aug 28 '15 at 18:51
  • I can confirm that using itemwidth on the VirtualizingWrapPanel now works! Thank you! However, the speed remains the same. About 5 seconds for 6k images @50KB. – NeoID Aug 28 '15 at 20:35
  • Interesting. I'm seeing sub-second time on my test project that is loading 10,000 images @1MB. All my images are coming from a local folder. In any case I just ran a Perfomance Explorer Profiler on the project and 39.1% of that time was spent executing the `child.Measure(childSlotSize)` function that comes from the PresentationFramework. If you remove the binding to `ItemWidth` the performance improves? If possible can you profile the code to see what is going on? – Cory Charlton Aug 28 '15 at 21:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/88232/discussion-between-cory-charlton-and-neoid). – Cory Charlton Aug 28 '15 at 21:20
  • Using this virtualizedWrapPanel inside an ItemsControl doesn't work. I believe the scroller is null – L Chougrani Jan 05 '21 at 12:50