Slow performance with WPF DataGrid and ScrollViewer
I have this style for a data grid:
<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>
I know that if you load a lot of data on a data grid, the performance suffers. I can use virtualization to mitigate that performance hit, however, as soon as I throw the grid in a custom scroll viewer, the virtualization is lost.
I am trying to get it back, but I'm not sure how -- while still retain the element named Image
in my XAML.
Basically, I want to have an image scrolling with the data grid contents and the above code works fine, it's just that I don't know how to enable virtualization. Is it even possible?
Update: Looks like I've found a problem. The last Grid
in the template causes a problem:
<Grid>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Grid.Row="0" />
<Canvas Width="128"
VerticalAlignment="Stretch"
HorizontalAlignment="Left"
Grid.Row="0"
x:Name="Image" />
</Grid>
As soon as I take the Canvas
and Grid
out, leaving only the ItemsPresenter
, then it's fast again. How can I get it fast and still retain this Canvas
?
Update 2: How can I apply this (ScrollViewer slow perfomance with DataGrid) strategy for my Grid
shown above? I tried this:
<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>
However, now the scrollbars have disappeared?
I realize that I can't virtualize a Canvas
, and I don't need to. In fact, the whole Canvas
gets drawn and I have no logic to separate it into smaller parts. It's completely fine to render the image at its entirety, as long as I can keep row virtualization.
I've got virtualization working for my custom control based on TreeView (.Net 4.0). I modified a little the style to match DataGrid, hope it is going to work for your case:
<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>
the problem is that virtualization only works if the contents of the scrollviewer supports IScrollInfo / VirtualizingPanel.
As far as I can see you want to have your items with a canvas with something below it - all inside your scrolling area. Is it actually a special kind of row you want? If so you could go that way and insert a special row instead? Or you could just move that outside the datagrid - or try using RowDetails - it is not the same apperance I know - but far easiere to use.
To get virtualization to work with what you have your canvas have to be inside the virtualizing panel.
链接地址: http://www.djcxy.com/p/10902.html