2012-06-20 8 views
7

que tiene este estilo de una cuadrícula de datos:Rendimiento lento con WPF DataGrid y ScrollViewer

<Setter Property="Template"> 
    <Setter.Value> 
     <ControlTemplate TargetType="{x:Type DataGrid}"> 
      <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True"> 
       <ScrollViewer x:Name="DG_ScrollViewer" Focusable="false"> 
        <ScrollViewer.Template> 
         <ControlTemplate TargetType="{x:Type ScrollViewer}"> 
          <Grid> 
           <Grid.ColumnDefinitions> 
            <ColumnDefinition Width="Auto"/> 
            <ColumnDefinition Width="*"/> 
            <ColumnDefinition Width="Auto"/> 
           </Grid.ColumnDefinitions> 
           <Grid.RowDefinitions> 
            <RowDefinition Height="Auto"/> 
            <RowDefinition Height="*"/> 
            <RowDefinition Height="Auto"/> 
           </Grid.RowDefinitions> 

           <DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" 
                   Grid.Column="1" 
                   Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/> 

           <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" 
                 CanContentScroll="{TemplateBinding CanContentScroll}" 
                 Grid.ColumnSpan="2" 
                 Grid.Row="1" /> 

           <ScrollBar x:Name="PART_VerticalScrollBar" 
              Grid.Column="2" 
              Maximum="{TemplateBinding ScrollableHeight}" 
              Orientation="Vertical" 
              Grid.Row="1" 
              Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" 
              ViewportSize="{TemplateBinding ViewportHeight}"/> 

           <Grid Grid.Column="1" Grid.Row="2"> 
            <Grid.ColumnDefinitions> 
             <ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/> 
             <ColumnDefinition Width="*"/> 
            </Grid.ColumnDefinitions> 

            <ScrollBar x:Name="PART_HorizontalScrollBar" 
               Grid.Column="1" 
               Maximum="{TemplateBinding ScrollableWidth}" 
               Orientation="Horizontal" 
               Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/> 
           </Grid> 
          </Grid> 
         </ControlTemplate> 
        </ScrollViewer.Template> 

        <Grid> 
         <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
             Grid.Row="0" /> 

         <Canvas Width="128" 
           VerticalAlignment="Stretch" 
           HorizontalAlignment="Left" 
           Grid.Row="0" 
           x:Name="Image" /> 
        </Grid> 
       </ScrollViewer> 
      </Border> 
     </ControlTemplate> 
    </Setter.Value> 
</Setter> 

sé que si se carga una gran cantidad de datos en una cuadrícula de datos, el rendimiento se resiente. Puedo usar la virtualización para mitigar ese golpe de rendimiento, sin embargo, tan pronto como lance la cuadrícula en un visor de desplazamiento personalizado, la virtualización se pierde.

Estoy tratando de recuperarlo, pero no estoy seguro de cómo - mientras todavía conservo el elemento llamado Image en mi XAML.

Básicamente, quiero tener una imagen desplazándose con los contenidos de la cuadrícula de datos y el código anterior funciona bien, es solo que no sé cómo habilitar la virtualización. ¿Es posible?

Actualización: Parece que he encontrado un problema. La última Grid en la plantilla provoca un problema:

<Grid> 
    <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
        Grid.Row="0" /> 

    <Canvas Width="128" 
      VerticalAlignment="Stretch" 
      HorizontalAlignment="Left" 
      Grid.Row="0" 
      x:Name="Image" /> 
</Grid> 

Tan pronto como tomo el Canvas y Grid, dejando sólo el ItemsPresenter, entonces es más rápido. ¿Cómo puedo obtenerlo rápido y aun así conservar este Canvas?

Actualización 2: ¿Cómo se puede aplicar esto (ScrollViewer slow perfomance with DataGrid) Estrategia para mi Grid se muestra arriba? He intentado esto:

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="*" /> 
    </Grid.RowDefinitions> 

    <Rectangle Name="sizingElement" Grid.Row="0" Fill="Transparent" Margin="1"/> 

    <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
        Grid.Row="0" 
        Height="{Binding ElementName=sizingElement, Path=ActualHeight, FallbackValue=1}" /> 

    <Canvas Width="128" 
      VerticalAlignment="Stretch" 
      HorizontalAlignment="Left" 
      Grid.Row="0" 
      x:Name="Image" /> 
</Grid> 

Sin embargo, ahora las barras de desplazamiento han desaparecido?

Me doy cuenta de que no puedo virtualizar un Canvas, y no es necesario. De hecho, todo el Canvas se dibuja y no tengo lógica para separarlo en partes más pequeñas. Está completamente bien renderizar la imagen en su totalidad, siempre que pueda mantener la virtualización de fila.

+0

yo no era consciente de cuadrícula admite la virtualización. ¿Cómo lo estás implementando? – NestorArturo

+0

Quise decir que DataGrid es compatible con la virtualización. – Tower

+1

Recuerdo algo sobre ScrollViewer en DataGrid rompiendo la virtualización DataGrid pero no puedo encontrarlo. Es solo de lectura Si es así, prueba GridView, es mucho más rápido. – Paparazzi

Respuesta

1

el problema es que la virtualización solo funciona si el contenido del scrollviewer es compatible con IScrollInfo/VirtualizingPanel.

Por lo que puedo ver, quiere tener sus artículos con un lienzo con algo debajo, todo dentro de su área de desplazamiento. ¿Es realmente un tipo especial de fila que quieres? Si es así, ¿podría ir de esa manera e insertar una fila especial en su lugar? O podría simplemente moverlo fuera de la cuadrícula de datos o intentar usar RowDetails, no es la misma apariencia que conozco, pero es muy fácil de usar.

Para que la virtualización funcione con lo que tiene que tener su lienzo debe estar dentro del panel de virtualización.

2

Tengo la virtualización funcionando para mi control personalizado basado en TreeView (.Net 4.0). He modificado un poco el estilo para que coincida con cuadrícula de datos, espero que va a trabajar para su caso:

<Style TargetType="{x:Type DataGrid}"> 
<Setter Property="OverridesDefaultStyle" Value="True" /> 
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True" /> 
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling" /> 
<Setter Property="BorderThickness" Value="1" /> 
<Setter Property="ItemsPanel"> 
    <Setter.Value> 
    <ItemsPanelTemplate> 
     <VirtualizingStackPanel IsItemsHost="True" VirtualizingStackPanel.IsVirtualizing="True" 
           VirtualizingStackPanel.VirtualizationMode="Recycling" /> 
    </ItemsPanelTemplate> 
    </Setter.Value> 
</Setter> 
<Setter Property="Template"> 
    <Setter.Value> 
      <ControlTemplate TargetType="{x:Type DataGrid}"> 
     <Border x:Name="Border" Grid.Column="0" Background="{TemplateBinding Background}" 
       BorderBrush="{StaticResource SolidBorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2"> 
     <DockPanel> 

      <ScrollViewer x:Name="PART_Body_Scroll" Background="White" HorizontalScrollBarVisibility="Auto" 
         VerticalScrollBarVisibility="Auto" CanContentScroll="True"> 

       <ItemsPresenter x:Name="ItemsHost" VirtualizingStackPanel.IsVirtualizing="True" 
          VirtualizingStackPanel.VirtualizationMode="Recycling" /> 

      </ScrollViewer> 

     </DockPanel> 
     </Border> 
    </ControlTemplate> 
    </Setter.Value> 
</Setter>