2

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. Performance Analysis Hot Path

Micah Hahn
  • 400
  • 2
  • 11
  • What you can try is to disable the Property notification on all the items, change all the properties, and then raise a NotifyCollectionChangedAction.Reset on the collection holding all the items. – dowhilefor Jan 16 '14 at 14:53
  • http://virtualwrappanel.codeplex.com/ – Bas Jan 16 '14 at 14:56
  • @dowhilefor Forgive my ignorance, but how do I raise `NotifyCollectionChangedAction.Reset` on an `ObservableCollection`? – Micah Hahn Jan 16 '14 at 15:07
  • @Micah Hahn, I tried your code in .NET 3.5 and .NET 4. It took me 2-3 seconds to check/uncheck 10000 checkboxes. – treehouse Jan 16 '14 at 15:14
  • @KaiWang Are you running an OS with Aero animations on? – Micah Hahn Jan 16 '14 at 15:16
  • @BasBrekelmans I've tried the VirtualWrapPanel, but haven't been able to get it to work. – Micah Hahn Jan 16 '14 at 15:18
  • @Micah Hahn, yes, win 7 with Aero on. If you suspect it's animation that causes this, why not restyle the checkbox to remove those animation? – treehouse Jan 16 '14 at 15:19
  • @Micah Hahn, 10+ seconds for 500 checkboxes is too slow even without visualization. – treehouse Jan 16 '14 at 15:21
  • @KaiWang Yes I agree its far too slow... I have considered restyling, but it appears you have to redo the entire template which I'm not particularly interested in. – Micah Hahn Jan 16 '14 at 15:29
  • @Micah Hahn, Restyling is just for proving your theory. Actually I doubt the problems lies on the default style. Restyling a control is pretty easy. What do you mean by "redo the entire template"? entire template of what? – treehouse Jan 16 '14 at 15:34
  • @KaiWang Can you give an example then? I had looked online before for examples on how to do so and didn't find anything that made it look easy. [link](http://stackoverflow.com/questions/4490421/turn-off-wpf-default-ui-animations-checkbox-etc) [link](http://social.msdn.microsoft.com/Forums/en-US/224ebb33-81db-44d3-bcbe-98873786df03/where-is-wpf-hiding-checkbox-checkmark-fade-inout-animation) – Micah Hahn Jan 16 '14 at 15:38

1 Answers1

0

I would look at the following control which is open source on CodePlex..

http://virtualwrappanel.codeplex.com/ (Note: I have no affilication with Virtualizing Wrap Panel)

Due to the large number of view models you are working with this would drastically improve performance for you.

BenjaminPaul
  • 2,931
  • 19
  • 18
  • As I mentioned in the comments above, I have not been able to get this custom control to work. I get the same exception mentioned here [WPF - Virtualising WrapPanel](http://stackoverflow.com/questions/3736989/wpf-virtualising-wrappanel), but the accepted answer did not fix it. – Micah Hahn Jan 16 '14 at 15:43