'C# WPF - Showing 15-20 User Controls with 4-6 TextBlocks each / Performance issues

I'm struggling with performance in my WPF application.

I have a ListView i populate with some buttons, which contain a bunch of TextBlocks with bindings. I managed to get Virtualization going, so it seems the same whether its 20 or 2000 i load.

The problem is between 5 and 20. It simply appears that rendering a bunch of somewhat complicated User Controls, is simply too much for basic sub-par hardware.

This is how my Buttons/UserControls in my ListView looks -> ListViewSample

I feel like WPF should be able to render this on sup-par hardware.

This is the xaml for the ListView:

<ListView ItemsSource="{Binding ButtonModels, IsAsync=True}"
                      Margin="0"
                      x:Name="ButtonsListView"
                      VirtualizingPanel.IsVirtualizing="True"
                      VirtualizingPanel.IsContainerVirtualizable="True"
                      VirtualizingPanel.VirtualizationMode="Recycling"
                      ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                      ScrollViewer.VerticalScrollBarVisibility="Auto"
                      SnapsToDevicePixels="True"
                      Background="Transparent"
                      BorderThickness="0">

            <ListView.Resources>
                <Style TargetType="ScrollBar">
                    <Setter Property="LayoutTransform">
                        <Setter.Value>
                            <ScaleTransform CenterX="0" CenterY="0"
                           ScaleX="3" ScaleY="3" />
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListView.Resources>
            <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                    <local:UniformGridPanel IsItemsHost="True" VerticalAlignment="Top" Height="Auto" Rows="4" Columns="{Binding Columns}" Margin="0">
                    </local:UniformGridPanel>
                </ItemsPanelTemplate>
                </ListView.ItemsPanel>
                
            <ListView.ItemContainerStyle>
                <Style TargetType="{x:Type ListViewItem}">
                    <Setter Property="Margin" Value="0"/>
                    <Setter Property="Padding" Value="0"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate>
                                <Button Height="117" Width="Auto" 
                                Margin="6,0,6,0" 
                                x:Name="MasterButton" 
                                Click="MasterButton_Click"
                                Visibility="{Binding IsVisible, Converter={StaticResource BoolToVis}}"
                                Template="{StaticResource ProductButtonTemplate}"
                                Padding="0">
                                </Button>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListView.ItemContainerStyle> 
            </ListView>

Here is the xaml for the Button template:

<ControlTemplate TargetType="{x:Type Button}" x:Key="ProductButtonTemplate">
            <UserControl>
                <Grid Background="Transparent">
                <Grid.RowDefinitions>
                    <RowDefinition Height="26"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <Border Grid.Row="0" Background="{Binding HeaderBrush}" CornerRadius="3,3,0,0">
                    <TextBlock VerticalAlignment="Center" FontSize="12" 
                                                   Text="{Binding DisplayName}" 
                                                   Foreground="{Binding FontIsWhite, Converter={StaticResource BoolToFontColour}}" 
                                                   FontFamily="{StaticResource DefaultRegular}"
                                                   Padding="8,0,0,0"/>
                </Border>
                <Border Grid.Row="1" Background="{StaticResource LightGrey}" CornerRadius="0,0,4,4" BorderBrush="{StaticResource BorderGrey}" BorderThickness="1">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>

                        <Grid.RowDefinitions>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="35" />
                        </Grid.RowDefinitions>

                        <TextBlock  Grid.Row="0" Grid.Column="0" 
                                                            FontSize="12" TextTrimming="CharacterEllipsis" Text="Nr.:" 
                                                            FontFamily="{StaticResource DefaultFont}"
                                                            VerticalAlignment="Center" HorizontalAlignment="Stretch"
                                                            Foreground="{StaticResource Black}"
                                                            Padding="8,0,0,0"/>
                        <TextBlock  Grid.Row="1" Grid.Column="0" 
                                                            FontSize="10" TextTrimming="CharacterEllipsis" Text="{Binding Combinations}" 
                                                            FontFamily="{StaticResource DefaultFont}"
                                                            VerticalAlignment="Center" HorizontalAlignment="Stretch"
                                                            Foreground="{StaticResource Black}"
                                                            Padding="8,0,0,0"/>
                        <TextBlock  Grid.Row="2" Grid.Column="0" 
                                                            FontSize="10" TextTrimming="CharacterEllipsis" Text="{Binding SizeAndColour}" 
                                                            FontFamily="{StaticResource DefaultFont}"
                                                            VerticalAlignment="Center" HorizontalAlignment="Stretch"
                                                            Foreground="{StaticResource Black}"
                                                            Padding="8,0,0,0"/>
                        <Grid Grid.Row="3" Grid.Column="0" 
                                                      Width="24" Height="24"
                                                      VerticalAlignment="Center" HorizontalAlignment="Left"
                                                      Margin="8,0,0,0"
                                                      Visibility="{Binding ShowStockValue, Converter={StaticResource BoolToVis}}">
                            <Ellipse Fill="{Binding StockStatus, Converter={StaticResource EnumToBrush}}" Stroke="{StaticResource LightGrey}" StrokeThickness="0.1">
                            </Ellipse>
                            <TextBlock Text="{Binding Stock}" 
                                                               Foreground="{StaticResource White}" 
                                                               FontSize="9" 
                                                               FontFamily="{StaticResource DefaultFont}"
                                                               VerticalAlignment="Center" HorizontalAlignment="Center"/>
                        </Grid>

                        <TextBlock  Grid.Row="0" Grid.Column="1" 
                                                            FontSize="12" TextTrimming="CharacterEllipsis" Text="{Binding ProductNr}"
                                                            Foreground="{StaticResource Black}"
                                                            VerticalAlignment="Center" HorizontalAlignment="Right"
                                                            FontFamily="{StaticResource DefaultFont}"
                                                            Padding="0,0,8,0"/>
                        <Label Grid.Row="3" Grid.Column="1" FontSize="13" 
                                                       Padding="0,0,8,8"
                                                       Content="{Binding Price}" 
                                                       Foreground="{StaticResource Black}"
                                                       FontWeight="Bold"
                                                       FontFamily="{StaticResource DefaultFont}"
                                                       VerticalContentAlignment="Bottom" HorizontalContentAlignment="Right"
                                                       ContentStringFormat="{}{0:#,0.00}" />
                    </Grid>
                </Border>
            </Grid>
            </UserControl>
        </ControlTemplate>

tldr; I'm looking for performance tips on how to make this render faster. And this is BEFORE i reach a size in the ListView where my virtualization kicks in (Which works flawlessly)

Thanks in advance!



Solution 1:[1]

I managed to find a high performance solution - it just wasn't what i would expect to be better performing.

So instead of having one ListView with a binding, changing the data in the binding and repopulating the Listview, i just spawn a ListView for every collection i have.

It seems weird to me, that having a bunch of ListViews and just collapsing and showing them is more effcient, but it performs absolutely flawlessly.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 HrRehmeier