I was previously using the code behind to manually add items to my ListBox, but it was terribly slow. I heard that data binding via XAML was the way to go, in terms of performance.
So I managed to get the data binding working (new to binding), but to my dismay, the performance is no better than my previous non-data binding method.
The idea is that my ListBox contains an Image with a name below it. I did some benchmarking and 54 items take a full 8 seconds to display. Which naturally is too long for a user to wait.
The source images are at a maxiumum: 2100x1535px and range from 400kb>4mb per file.
The images required to reproduce this issue can be found here: Link removed as question has been answered and my server doesn't have very much bandwidth allowance. Other image source here: https://i.stack.imgur.com/iS0h0.jpg
I've made a reproducible example of the issue below. What am I doing wrong that is making this so slow?
Thank you.
The XAML:
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="800" WindowState="Maximized">
    <Grid>
        <ListBox x:Name="listBoxItems" ItemsSource="{Binding ItemsCollection}"
                    ScrollViewer.HorizontalScrollBarVisibility="Disabled">
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel IsItemsHost="True" />
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <VirtualizingStackPanel>
                        <Image Width="278" Height="178">
                            <Image.Source>
                                <BitmapImage DecodePixelWidth="278" UriSource="{Binding ImagePath}" CreateOptions="IgnoreColorProfile" />
                            </Image.Source>
                        </Image>
                        <TextBlock Text="{Binding Name}" FontSize="16" VerticalAlignment="Bottom" HorizontalAlignment="Center" />
                    </VirtualizingStackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>
The code behind:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Threading;
namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        internal class Item : INotifyPropertyChanged
        {
            public Item(string name = null)
            {
                this.Name = name;
            }
            public string Name { get; set; }
            public string ImagePath { get; set; }
            public event PropertyChangedEventHandler PropertyChanged;
            private void NotifyPropertyChanged(String propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
        ObservableCollection<Item> ItemsCollection;
        List<Item> data;
        public MainWindow()
        {
            InitializeComponent();
            this.data = new List<Item>();
            this.ItemsCollection = new ObservableCollection<Item>();
            this.listBoxItems.ItemsSource = this.ItemsCollection;
            for (int i = 0; i < 49; i ++)
            {
                Item newItem = new Item
                {
                    ImagePath = String.Format(@"Images/{0}.jpg", i + 1),
                    Name = "Item: " + i
                };
                this.data.Add(newItem);
            }
            foreach (var item in this.data.Select((value, i) => new { i, value }))
            {
                Dispatcher.Invoke(new Action(() =>
                {
                    this.ItemsCollection.Add(item.value);
                }), DispatcherPriority.Background);
            }
        }
    }
}
 
     
     
     
    