2014-03-12 75 views
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的。 example

当我的绑定数据越来越多(比如第一个列表中的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> 
+0

第一个问题:你有没有任何绑定错误?此外,作为性能的一般规则,请尝试查看是否可以将某些网格列宽或行高更改为静态值。如果这是可能的,并且它确实在性能上有明显的差异,我会认为你的性能问题与尺寸计算有关。我有使用ItemsControl和复杂模板的相同问题,并通过静态尺寸修复了很多问题。 – JFTxJ

+0

另外,请记住,虚拟化会告诉系统在滚动时进行计算。如果关闭虚拟化,应用程序的性能如何?加载列表的速度非常慢。当您滚动时,原始负载会不会更好然后落后? – JFTxJ

+0

此外,由于您的项目具有不同的高度,请记住,这通常意味着WPF必须关闭虚拟化,因为如果不知道显示项目的整个高度,无法知道滚动条的大小。它必须呈现列表中的所有项目以了解实际项目列表的高度,因此它可以计算滚动条的大小... – JFTxJ

回答

0

完成;看到我最后的评论。 扩展器风格造成了一些麻烦。