2014-03-12 73 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

完成;看到我最後的評論。 擴展器風格造成了一些麻煩。