I am new in WPF and read a lot about performance issues. I have some issues on some program with a lot of styles using mah apps and other 3rd party controls. So I created a simple test. Please see the code above. This code works fine. Takes about 1 second to load. Changing the for loop to 1,000 items, will take about 2-3 seconds and 10,000 items about 8 seconds to load. I don't understand why. I configured virtualziation that means to draw only the visible rows. It should take the same time for initialization. I don't have any style or heavy controls. All the WPF mvvm concept is very helpful but I can't use it if I have a lot of performance issues.
UPDATE The ListView
loads 10,000 items fast (up to 1 sec), the problem is the items control. How can I overcome this? in my real application I should use the item control. I can see in the profiler that wihout the ItemsControl
the memory is stable around 166MB and with the ItemsControl
is always increasing. I can't understandm according to the articles ListView
and ListBox
are derived from ItemsControl
.
View Model:
public ViewModel()
{
for(int i = 0; i < 100; i ++)
{
Collection.Add(new Person()
{
FirstName = $"FirstName{i}",
LastName = $"LastName{i}",
Gender = $"Gender{i}",
});
}
Title = "Title";
IsVisible = true;
}
public ObservableCollection<Person> Collection { get; } = new ObservableCollection<Person>();
private string _title;
public string Title
{
get { return _title; }
set
{
if(_title != value)
{
_title = value;
OnPropertyChanged();
}
}
}
private bool _isVisible;
public bool IsVisible
{
get { return _isVisible; }
set
{
if (_isVisible != value)
{
_isVisible = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
Window:
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:ViewModel}"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate x:Name="ItemTemplate" DataType="{x:Type local:Person}">
<Grid ScrollViewer.VerticalScrollBarVisibility="Visible"
VirtualizingPanel.IsVirtualizing="True">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Margin="3,5,6,0" Text="{Binding FirstName}" Background="Red"/>
<TextBlock Margin="3,5,6,0" Text="{Binding LastName}" Background="Yellow"/>
<TextBlock Margin="3,5,6,0" Text="{Binding Gender}" Background="Beige"/>
</Grid>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ListView ItemsSource="{Binding Collection}" Height="250" ScrollViewer.VerticalScrollBarVisibility="Auto"
VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="3,5,6,0" Text="{Binding FirstName}" Background="Blue"/>
<TextBlock Margin="3,5,6,0" Text="{Binding LastName}" Background="Yellow"/>
<TextBlock Margin="3,5,6,0" Text="{Binding Gender}" Background="Beige"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ItemsControl
ItemsSource="{Binding Collection}"
ItemTemplate="{Binding ItemTemplate}"
VirtualizingPanel.IsVirtualizing="True">
</ItemsControl>
</StackPanel>
</Window>
Update 2
After the comment to avoid using StackPanel (without height), I tried to use only the ItemsControl
with fix height and without any panel (only a TextBlock
). Now it takes 5 seconds instead of 8 seconds.
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:ViewModel}"
Title="MainWindow" Height="450" Width="800"
Loaded="Window_Loaded">
<Window.Resources>
<DataTemplate x:Name="ItemTemplate" DataType="{x:Type local:Person}">
<TextBlock Margin="3,5,6,0" Text="{Binding FirstName}" Background="Blue"/>
</DataTemplate>
</Window.Resources>
<ItemsControl
ItemsSource="{Binding Collection}"
Height="250"
VirtualizingPanel.IsContainerVirtualizable="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.CacheLengthUnit="Item">
</ItemsControl>
</Window>
blame StackPanel. It tells ItemsControl it can use infinite Height, so no virtualization. You don't have problem with ListView, because it has explicit Height="250".
A simple fix is to use Grid (and not row Height="Auto", it will result in the same behavior):
<Window ...>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListView Grid.Row="0" ...>
<ScrollViewer Grid.Row="1">
<ItemsControl ...>
</ScrollViewer>
</Grid>
</Window>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.