【问题标题】:WPF ListBox Virtualization and Mulltiple types in the ItemsControlWPF ListBox 虚拟化和 ItemsControl 中的多种类型
【发布时间】:2014-04-08 19:27:46
【问题描述】:

我有一个 ListBox,用于显示通过 ObservableCollection<T> 绑定到 ItemsSource 的多种类型的项目(都派生自同一个基类型)。

说的 ListBox 的性能很糟糕。似乎禁用了虚拟化。根据:http://msdn.microsoft.com/en-us/library/cc716879(v=vs.110).aspx 看来,向 ItemsControl 添加多种类型的项目可能是问题所在。

这是我的 ListBox 的样式:

<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>

绑定ObservableCollection&lt;T&gt; 中的每种可能类型都有DataTemplates,它们都是派生自同一个基类的类。一个示例 DataTemplate 是:

<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 在这里:

<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>

WPF 窗口的层次结构是:

<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>

是否有解决此问题的方法,或者任何人都可以看到任何其他可能关闭虚拟化的原因?

您可以下载an example project here

谢谢。

【问题讨论】:

  • 添加不同类型的数据项不会影响虚拟化。 MSDN 说:Item containers 直接添加到 ItemsControl。。例如,那将是 ListBoxItemComboBoxItem
  • 确保您没有将 ListBox 放入“无限容器”,例如 StackPanel 或 ScrollViewer。发布 ListBox 所在的 UI 的完整 XAML。
  • 另外,你的数据项是什么类型的?
  • 所有数据项都派生自同一个基类。 ListBox 位于以 Grid 作为其容器的 UserControl 内部。
  • 用户控件包含在几个网格和一个 GroupBox 中,但没有 StackPanels

标签: .net wpf xaml listbox virtualization


【解决方案1】:

通过删除带有SharedSizeGroupsColumnDefinitions显着提高了示例项目的性能:

<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>

SharedSizeGroup 所需的计算量太大,如果您有大量项目,应避免使用。

改用ListView

【讨论】:

  • ListBox 让我可以为列表中的每种数据类型使用不同的模板。有些类型有不同的背景颜色,有时第一列是图像,有时使用列跨度等。这就是为什么选择此方案而不是 ListView。
  • 我已经确认性能问题确实与网格列上的 SharedSizeGroup 属性有关。 ListBox 上的虚拟化似乎从来都不是问题。感谢您的回答!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-16
  • 2023-03-16
  • 2010-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多