I've a performance problem with an ItemsControl. I've virtualized the ItemsControl using the following style
<Style x:Key="VirtualizedItemsControl"
TargetType="{x:Type ItemsControl}">
<Setter Property="VirtualizingStackPanel.IsVirtualizing"
Value="True" />
<Setter Property="ScrollViewer.CanContentScroll"
Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
SnapsToDevicePixels="True">
<ScrollViewer Padding="{TemplateBinding Control.Padding}"
Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
My ItemsTemplate is an Expander with another ItemsControl which ItemsTemplate is an Expander with a DataGrid (DataContext is a list in a list).
When my bound data is getting more (like 100 entries in the first list and in each datagrid ~100 entries) the ui is getting really slow if i start to scroll. I don't know why it's getting so slow.
I change the background color of each DataGrid cell if there are changes. That's why I use DataGridTemplateColumns.
<ItemsControl ItemsSource="{Binding MyList}"
x:Name="_container"
Style="{StaticResource VirtualizedItemsControl}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander>
<Expander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock />
<Button Grid.Column="1"
Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext.DeleteCommand}"
CommandParameter="{Binding}">
<Image Source="trashcan-delete.png"
HorizontalAlignment="Right" />
</Button>
</Grid>
</Expander.Header>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label Content="Some text" />
<ComboBox Grid.Column="1"
Margin="5 0"
Width="150"
HorizontalAlignment="Left"
Text="{Binding Name.Property}"
SelectedItem="{Binding SelectedName, UpdateSourceTrigger=PropertyChanged}"
Foreground="Black"
IsEditable="True"
DisplayMemberPath="Name"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext.Children}"
Background="{Binding Name.IsDirty, Converter={StaticResource IsDirtyToColorConverter}}" />
</Grid>
<ItemsControl Grid.Row="1"
ItemsSource="{Binding ParameterBlocks}"
Style="{StaticResource VirtualizedItemsControl}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander>
<Expander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Index, Converter={StaticResource NumberToBlockHeaderConverter}}"
FontWeight="Bold"
Foreground="White" />
<Button Grid.Column="1"
Command="{Binding RelativeSource={RelativeSource AncestorType=Expander, AncestorLevel=2}, Path=DataContext.DeleteBlockCommand}"
CommandParameter="{Binding}">
<Image Source="trashcan-delete.png"
HorizontalAlignment="Right" />
</Button>
</Grid>
</Expander.Header>
<Grid Background="#E5E5E5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0"
Content="Some text"
VerticalAlignment="Center"
IsChecked="{Binding IsWaitingEnabled.Property}"
Background="{Binding IsWaitingEnabled.IsDirty, Converter={StaticResource IsDirtyToColorConverter}}">
<Label Grid.Column="1"
Margin="15 0 0 0"
VerticalAlignment="Center"
Content="Some text"
IsEnabled="{Binding IsWaitingEnabled.Property}" />
<Xctk:IntegerUpDown Grid.Column="2"
Minimum="0"
Width="60"
Margin="5 0 0 0"
HorizontalAlignment="Left"
Text="Some text"
IsEnabled="{Binding IsWaitingEnabled.Property}"
</Grid>
<DataGrid ItemsSource="{Binding Channels}"
Style="{StaticResource StandardGridStyle}"
x:Name="BlockGrid"
Grid.Row="1"
CanUserSortColumns="True"
Margin="5 0"
MaxHeight="200"
SelectedItem="{Binding SelectedEntry}"
CanUserAddRows="True">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Some text"
Width="200">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Channel.Property, UpdateSourceTrigger=PropertyChanged}"
Foreground="Black"
Background="{Binding Channel.IsDirty, Converter={StaticResource IsDirtyToColorConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Text="{Binding Channel.Property, UpdateSourceTrigger=PropertyChanged}"
Foreground="Black"
IsEditable="True"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Expander}, AncestorLevel=2}, Path=DataContext.SelectedChannelList.Channels}"
IsEnabled="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=DataContext.IsPasswordProtected, Converter={StaticResource BoolToOppositeBoolConverter}}"
Background="{Binding Channel.IsDirty, Converter={StaticResource IsDirtyToColorConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Some text"
Width="150"
Foreground="Black"
Binding="{Binding Value.Property, UpdateSourceTrigger=PropertyChanged}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Value.IsDirty}"
Value="true">
<Setter Property="Background"
Value="#FFDDA203" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTemplateColumn Header="Some text">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Block.Property}"
Foreground="Black"
Background="{Binding Block.IsDirty, Converter={StaticResource IsDirtyToColorConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<Xctk:IntegerUpDown Minimum="1"
Maximum="{Binding RelativeSource={RelativeSource AncestorType={x:Type Expander}, AncestorLevel=2}, Path=DataContext.ParameterBlocks, Converter={StaticResource ListToCountConverter}}"
Text="{Binding Block.Property, UpdateSourceTrigger=PropertyChanged}"
Background="{Binding Block.IsDirty, Converter={StaticResource IsDirtyToColorConverter}}">
<I:Interaction.Triggers>
<I:EventTrigger EventName="ValueChanged">
<Commands:EventToCommand Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Expander}, AncestorLevel=2}, Path=DataContext.BlockChangedCommand}"
CommandParameter="{Binding }" />
</I:EventTrigger>
</I:Interaction.Triggers>
</Xctk:IntegerUpDown>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<I:Interaction.Behaviors>
<Commands:DataGridScrollToSelectedItemBehavior />
</I:Interaction.Behaviors>
</DataGrid>
<StackPanel Grid.Row="2"
Margin="5"
Orientation="Horizontal"
HorizontalAlignment="Right">
<Button Command="{Binding DeleteEntryCommand}"
Content="Some text"
CommandParameter="{Binding ElementName=BlockGrid, Path=SelectedItems}"
Width="120"
Margin="5 0" />
<Button Content="Some text"
Command="{Binding AddEntryCommand}"
Width="120"
Margin="5 0"
HorizontalAlignment="Right" />
</StackPanel>
</Grid>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Done; see my last comment. The Expander style was making some trouble.