Search code examples
wpftemplatesdatagridwpfdatagridscrollviewer

About re-templating correctly DataGrid


I recently had this problem about scrolling and focus changing.

I solved it by adding in my DataGrid the following:

            <DataGrid.Template>
                <ControlTemplate>

                    <ItemsPresenter />
                </ControlTemplate>

            </DataGrid.Template>

The scrolling now works fine, but a new problem appeared: the DataGrid's headers do not show anymore. It is actually logic, since now my DataGrid will only show an ItemsPresenter without taking care of the headers. I am therefore trying to define an appropriate template, showing first the headers and then the items in an ItemsPresenter, allowing me to scroll easily. Am I just missing something, or is that a different property to override?

Thanks!


Solution

  • This is what the default DataGrid template looks like (in the Classic theme):

    <ControlTemplate TargetType="{x:Type DataGrid}">
        <Border Background="{TemplateBinding Background}"
          BorderBrush="{TemplateBinding BorderBrush}"
          BorderThickness="{TemplateBinding BorderThickness}"
          SnapsToDevicePixels="True"
          Padding="{TemplateBinding Padding}">
            <ScrollViewer   Focusable="false"
                    Name="DG_ScrollViewer">
                <ScrollViewer.Template>
                    <ControlTemplate TargetType="{x:Type ScrollViewer}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
    
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
    
                            <Button Command="{x:Static DataGrid.SelectAllCommand}"
                                    Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=CellsPanelHorizontalOffset}"
                                    Style="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type DataGrid}, ResourceId=DataGridSelectAllButtonStyle}}"
                                    Focusable="false"
                                    Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.All}}" />
                            <DataGridColumnHeadersPresenter Grid.Column="1" 
                                               Name="PART_ColumnHeadersPresenter"
                                               Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Column}}"/>
    
                            <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Grid.Row="1" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" />
    
                            <ScrollBar Grid.Row="1" Grid.Column="2" Name="PART_VerticalScrollBar"
                                     Orientation="Vertical"
                                     Maximum="{TemplateBinding ScrollableHeight}"
                                     ViewportSize="{TemplateBinding ViewportHeight}"
                                     Value="{Binding Path=VerticalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
                                     Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
    
                            <Grid Grid.Row="2" Grid.Column="1">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=NonFrozenColumnsViewportHorizontalOffset}"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <ScrollBar Grid.Column="1"
                                           Name="PART_HorizontalScrollBar"
                                           Orientation="Horizontal"
                                           Maximum="{TemplateBinding ScrollableWidth}"
                                           ViewportSize="{TemplateBinding ViewportWidth}"
                                           Value="{Binding Path=HorizontalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
                                           Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
    
                            </Grid>
                        </Grid>
                    </ControlTemplate>
                </ScrollViewer.Template>
                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
            </ScrollViewer>
        </Border>
    </ControlTemplate>
    

    Notice that it uses a DataGridColumnHeadersPresenter. You will want to add this to your template as well.