Вопрос

I've got a ListBox that is used to show items of multiple types (all derived from the same base type) that are bound to the ItemsSource through an ObservableCollection<T>.

The performance of said ListBox is terrible. It appears that virtualization is disabled. According to: http://msdn.microsoft.com/en-us/library/cc716879(v=vs.110).aspx it seems that adding items of multiple types to the ItemsControl may be the problem.

Here's my ListBox's style:

<Style x:Key="{x:Type ListBox}" TargetType="{x:Type ListBox}">
        <Setter Property="ScrollViewer.CanContentScroll" Value="true" />
        <Setter Property="VirtualizingPanel.VirtualizationMode" Value="Recycling" />
        <Setter Property="VirtualizingPanel.IsVirtualizing" Value="True" />
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Visible" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBox">
                    <Grid Grid.IsSharedSizeScope="True">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>

                        <ContentPresenter Content="{StaticResource ListHeader}" />

                        <ScrollViewer Grid.Row="1" Margin="0" Focusable="False">
                            <VirtualizingStackPanel Margin="2" IsItemsHost="True" />
                        </ScrollViewer>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

There are DataTemplates for each of the possible types in the bound ObservableCollection<T> and they are all classes that derive from the same base class. An example DataTemplate is:

<DataTemplate DataType="{x:Type ma:TimerEvent}">
            <Grid Background="{StaticResource TargetCalledBackgroundColor}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" SharedSizeGroup="ShotNumberColumn" />
                    <ColumnDefinition Width="Auto" SharedSizeGroup="ShotTimeColumn" />
                    <ColumnDefinition Width="Auto" SharedSizeGroup="SplitTimeColumn" />
                    <ColumnDefinition Width="Auto" SharedSizeGroup="TargetNumberColumn" />
                    <ColumnDefinition Width="Auto" SharedSizeGroup="TotalTimeColumn" />
                    <ColumnDefinition Width="Auto" SharedSizeGroup="ScoreColumn" />
                </Grid.ColumnDefinitions>

                <Image Source="/LASR;component/Assets/Announcement.png" Width="16" Height="16" HorizontalAlignment="Center" VerticalAlignment="Center" />
                <TextBlock Grid.Column="1" Grid.ColumnSpan="2" Foreground="{StaticResource TargetCalledForegroundColor}" Text="{Binding DisplayText}" TextAlignment="Center" />
                <TextBlock Grid.Column="3" Foreground="{StaticResource TargetCalledForegroundColor}" Text="{Binding TargetNumberCalled}" TextAlignment="Center" />
                <TextBlock Grid.Column="4" Foreground="{StaticResource TargetCalledForegroundColor}" Text="{Binding Path=TotalTime.TotalSeconds, StringFormat={}{0:0.00}}" TextAlignment="Center" />
            </Grid>
        </DataTemplate>

ListBox XAML is here:

<UserControl>
<Grid>
    <ListBox ItemsSource="{Binding}">
            <ListBox.ItemContainerStyle>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                </Style>
            </ListBox.ItemContainerStyle>
        </ListBox>
</Grid>
</UserControl>

The WPF window's hierarchy is:

<Window>
<Grid>
 <Grid Name="MainWindowContent">
  <Grid.RowDefinitions>
   <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
    <RowDefinition Height="Auto" />
   </Grid.RowDefinitions>
   <Grid.ColumnDefinitions>
    <ColumnDefinition Width="340*" />
    <ColumnDefinition Width="Auto" />
   </Grid.ColumnDefinitions>
   <GroupBox Grid.Row="1" Grid.Column="1">
    <Grid>
     <Grid.RowDefinitions>
      <RowDefinition Height="*" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
     </Grid.RowDefinitions>
     <UserControl />
    </Grid>
   </GroupBox>
  </Grid>
 </Grid>
</Window>

Is there a solution to this problem or can anyone see any other reason virtualization may be turned off?

You can download an example project here.

Thanks.

Это было полезно?

Решение

Performance in your sample project is drastically improved by removing the ColumnDefinitions with SharedSizeGroups:

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" SharedSizeGroup="ShotNumberColumn" />
    <ColumnDefinition Width="Auto" SharedSizeGroup="ShotTimeColumn" />
    <ColumnDefinition Width="Auto" SharedSizeGroup="SplitTimeColumn" />
    <ColumnDefinition Width="Auto" SharedSizeGroup="TargetNumberColumn" />
    <ColumnDefinition Width="Auto" SharedSizeGroup="TotalTimeColumn" />
    <ColumnDefinition Width="Auto" SharedSizeGroup="ScoreColumn" />
</Grid.ColumnDefinitions>

The calculations needed for SharedSizeGroup are too heavy and should be avoided if you have large number of items.

Use a ListView instead.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top