0
我有一个ItemsControl的性能问题。我用下面的风格ItemsControl和复杂ItemTemplate的性能问题
<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>
我ItemsTemplate与另一个ItemsControl的这ItemsTemplate是一个DataGrid的扩展(DataContext的是在一个列表的列表)的扩展虚拟化的ItemsControl的。
当我的绑定数据越来越多(比如第一个列表中的100个条目和每个数据网格~100个条目)时,如果我开始滚动,ui变得非常慢。 我不知道为什么它变得如此缓慢。
如果有更改,我更改每个DataGrid单元格的背景颜色。这就是我使用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>
第一个问题:你有没有任何绑定错误?此外,作为性能的一般规则,请尝试查看是否可以将某些网格列宽或行高更改为静态值。如果这是可能的,并且它确实在性能上有明显的差异,我会认为你的性能问题与尺寸计算有关。我有使用ItemsControl和复杂模板的相同问题,并通过静态尺寸修复了很多问题。 – JFTxJ
另外,请记住,虚拟化会告诉系统在滚动时进行计算。如果关闭虚拟化,应用程序的性能如何?加载列表的速度非常慢。当您滚动时,原始负载会不会更好然后落后? – JFTxJ
此外,由于您的项目具有不同的高度,请记住,这通常意味着WPF必须关闭虚拟化,因为如果不知道显示项目的整个高度,无法知道滚动条的大小。它必须呈现列表中的所有项目以了解实际项目列表的高度,因此它可以计算滚动条的大小... – JFTxJ