I'm in a bit of a bind here (no pun intended); I have a large collection of view models (500+) which are displayed using an ItemsControl
with a WrapPanel
as the ItemsPanelTemplate
. Each of these view models exposes a Boolean?
whose value is bound to the IsChecked
property of a CheckBox
on the user interface.
The problem is this... whenever I attempt to update all the checkboxes at once it is horrendously slow. Almost 10 seconds to update a list of 500 items. If I run the updating code in a seperate thread I can almost watch the checkboxes be updated one by one.
Can anyone enlighten me as to why this process is so slow and how I could improve it?
I have considered that perhaps the non-virtualizing nature of the WrapPanel
could be the guilty party. However, when I bind to the IsEnabled
property instead of IsChecked
I see an interesting result; namely that changing the value of IsEnabled
to true is slow as expected, but changing to false happens instantaneously. This makes me suspicious that the checkbox animation is at fault because as far as I can tell visually there is no animation when disabling a checkbox, but there is when enabling. Profiling has revealed that the vast majority of time is spent in the PropertyChangedEventManager.OnPropertyChanged()
method.
Example code below, I'm unfortunately forced to use .NET 3.5:
XAML:
<ItemsControl ItemsSource="{Binding ChildItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type SampleViewModel}">
<CheckBox IsThreeState="True" IsChecked="{Binding Path=IncludeInPrinting, Mode=OneWay}" />
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
ViewModel:
public class SampleViewModel : INotifyPropertyChanged
{
private Boolean? _includeInPrinting;
public Boolean? IncludeInPrinting
{
get
{
return _includeInPrinting;
}
set
{
if (_includeInPrinting != value)
{
_includeInPrinting = value;
RaisePropertyChanged(() => IncludeInPrinting);
}
}
}
}
Slow Code:
foreach (SampleViewModel model in ChildItems)
{
model.IncludeInPrinting = false;
}
EDIT: For what it's worth I'm also seeing a spike in memory usage whenever I check all or uncheck all the checkboxes. ~10MB
EDIT: The performance analysis below seems to confirm that animation is definitely the issue.