I have a more complex code on my hand, but to ask this question I am bringing a simpler example of code.
My App is going to iterate throughout all glyphs in a specific font (expected 500 to 5000 glyphs). Each glyph should have a certain custom visual, and some functionality in it. For that I thought that best way to achieve that is to create a UserControl
for each glyph.
On the checking I have made, as my UserControl
gets more complicated, it takes more time to construct it. Even a simple adding of Style
makes a meaningful effect on the performance.
What I have tried in this example is to show in a ListBox
2000 glyphs. To notice the performance difference I put 2 ListBoxes - First is binding to a simple ObservableCollection
of string. Second is binding to ObservableCollection
of my UserControl.
This is my MainWindow
xaml:
<Grid Background="WhiteSmoke">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<ListBox Margin="10" ItemsSource="{Binding MyCollection}"></ListBox>
<ListBox Margin="10" Grid.Row="1" ItemsSource="{Binding UCCollection}"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"></ListBox>
</Grid>
On code behind I have 2 ObservableCollection
as mentioned:
public static ObservableCollection<string> MyCollection { get; set; } = new ObservableCollection<string>();
public static ObservableCollection<MyUserControl> UCCollection { get; set; } = new ObservableCollection<MyUserControl>();
For the first List of string
I am adding like this:
for (int i = 0; i < 2000; i )
{
string glyph = ((char)(i 33)).ToString();
string hex = "U " i.ToString("X4");
MyCollection.Add($"Index {i}, Hex {hex}: {glyph}");
}
For the second List of MyUserControl
I am adding like this:
for (int i = 0; i < 2000; i )
{
UCCollection.Add(new MyUserControl(i 33));
}
MyUserControl
xaml looks like this:
<Border Background="Black" BorderBrush="Orange" BorderThickness="2" MinWidth="80" MinHeight="80">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="2*"></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock HorizontalAlignment="Center" Foreground="White" FontSize="40" Text="{Binding Glyph}"/>
<TextBlock HorizontalAlignment="Center" Foreground="OrangeRed" Text="{Binding Index}" Grid.Row="1"/>
<TextBlock HorizontalAlignment="Center" Foreground="White" Text="{Binding Hex}" Grid.Row="2"/>
</Grid>
</Border>
And code behind of MyUserControl
:
public partial class MyUserControl : UserControl
{
private int OrgIndex { get; set; } = 0;
public string Hex => "U " OrgIndex.ToString("X4");
public string Index => OrgIndex.ToString();
public string Glyph => ((char)OrgIndex).ToString();
public MyUserControl(int index)
{
InitializeComponent();
OrgIndex = index;
}
}
In order to follow the performance issue I have used Stopwatch
. Adding 2000 string items to the first list took 1ms. Adding 2000 UserControls to the second list took ~1100ms. And it is just a simple UserControl, when I add some stuff to it, it takes more time and performance getting poorer. For example if I just add this Style
to Border
time goes up to ~1900ms:
<Style TargetType="{x:Type Border}" x:Key="BorderMouseOver">
<Setter Property="Background" Value="Black" />
<Setter Property="BorderBrush" Value="Orange"/>
<Setter Property="MinWidth" Value="80"/>
<Setter Property="MinHeight" Value="80"/>
<Setter Property="BorderThickness" Value="2" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" Value="True">
<Setter Property="Background" Value="#FF2A3137" />
<Setter Property="BorderBrush" Value="#FF739922"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
I am not fully familiar with WPF work around, so I will really appreciate your help. Is this a totally wrong way to do this? I have read some posts about it, but could not manage to go through this: