You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复WPF DataGrid滚动条与列标题连接处的空白区域?

WPF DataGrid滚动条顶部与列头间空白区域填充方案

我用WPF的DataGrid展示数据,数据行数较多时会出现滚动条,滚动条顶部和DataGrid的ColumnHeader连接处存在一块空白区域,希望用列头样式或其他美观内容填充该区域,请问该如何实现?

滚动条顶部与列头间的空白区域

我的DataGrid代码

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="100"/>
        <RowDefinition />
        <RowDefinition Height="150"/>
    </Grid.RowDefinitions>

    <StackPanel Grid.Row="1" Orientation="Horizontal">
        <DataGrid x:Name="DataGrid"
                  ItemsSource="{Binding ProfilesDataGrid}"
                  Style="{StaticResource DataGrid_Style}"
                  CellStyle="{StaticResource DataGridCell_Style}"
                  RowStyle="{StaticResource DataGridRow_Style}"
                  RowHeaderStyle="{StaticResource DataGridRowHeader_Style}"
                  ColumnHeaderStyle="{StaticResource DataGridColHeader_Style}">

            <!-- Data Grid Columns -->
            <DataGrid.Columns>
                <DataGridTextColumn Header="Status" 
                                    Binding = "{Binding ProfileStatus}"
                                    Width="50"
                                    ElementStyle="{StaticResource DataGridCellCenter_Style}"/>
                <DataGridTextColumn Header="Profile" 
                                    Binding = "{Binding ProfileName}"
                                    MinWidth="125"/>
                <DataGridTextColumn Header="Email" 
                                    Binding = "{Binding ProfileEmail}"
                                    Width="*"/>
                <DataGridTemplateColumn Header=""
                                        Width="60">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Button x:Name="EditProfileButton"
                                        BorderThickness="0"
                                        Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
                                    <Image Source="../Resources/Images/icon_edit.png"/>
                                </Button>
                                <Button x:Name="DeleteProfileButton"
                                        BorderThickness="0"
                                        Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
                                    <Image Source="../Resources/Images/icon_delete.png"/>
                                </Button>
                            </StackPanel>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </StackPanel>
</Grid>

我之前看到有帖子用ScrollContentPresenter解决这个问题,但因为我绑定了ItemSource,没法用这个方案,想知道原因是什么?

我的样式资源代码

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <!-- Data Grid -->
    <Style x:Key="DataGrid_Style" TargetType="{x:Type DataGrid}">
        <Setter Property="Foreground" Value="WhiteSmoke"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="HorizontalAlignment" Value="Left"/>
        <Setter Property="AutoGenerateColumns" Value="False"/>
        <Setter Property="CanUserReorderColumns" Value="False"/>
        <Setter Property="CanUserResizeColumns" Value="False"/>
        <Setter Property="CanUserResizeRows" Value="False"/>
        <Setter Property="CanUserAddRows" Value="False"/>
        <Setter Property="CanUserDeleteRows" Value="False"/>
        <Setter Property="IsReadOnly" Value="True"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Width" Value="500"/>
        <Setter Property="Margin" Value="50 20"/>
        <Setter Property="BorderBrush" Value="#343b48"/>
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="GridLinesVisibility" Value="All"/>
        <Setter Property="SelectionMode" Value="Single"/>
        <Setter Property="SelectionUnit" Value="FullRow"/>
        <Setter Property="HorizontalGridLinesBrush" Value="#2c313c"/>
        <Setter Property="VerticalGridLinesBrush" Value="#2c313c"/>
    </Style>

    <!-- Cell -->
    <Style x:Key="DataGridCell_Style" TargetType="{x:Type DataGridCell}">
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    </Style>

    <!-- Row -->
    <Style x:Key="DataGridRow_Style" TargetType="{x:Type DataGridRow}">
        <Setter Property="Background" Value="#343b48"/>
        <Setter Property="Height" Value="25" />
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Background" Value="#839096"/>
                <Setter Property="Foreground" Value="Black"/>
            </Trigger>
        </Style.Triggers>
    </Style>

    <!-- Row Header -->
    <Style x:Key="DataGridRowHeader_Style" TargetType="{x:Type DataGridRowHeader}">
        <Setter Property="Width" Value="0"/>
    </Style>

    <!-- Column Header -->
    <Style x:Key="DataGridColHeader_Style" TargetType="{x:Type DataGridColumnHeader}">
        <Setter Property="Background" Value="#1a95d4"/>
        <Setter Property="HorizontalContentAlignment" Value="Left"/>
        <Setter Property="Height" Value="25"/>
    </Style>
    
    <!-- Cell Centered -->
    <Style x:Key="DataGridCellCenter_Style" TargetType="{x:Type TextBlock}">
        <Setter Property="HorizontalAlignment" Value="Center"/>
    </Style>
</ResourceDictionary>

解决方案

方法1:修改DataGrid的ControlTemplate(推荐)

空白区域是DataGrid默认模板中ScrollViewer与列头容器的间隙,或是滚动条顶部未被覆盖的区域。重写DataGrid的ControlTemplate,添加一个与列头同背景的元素覆盖空白即可:

将以下模板整合到你的DataGrid_Style中:

<Style x:Key="DataGrid_Style" TargetType="{x:Type DataGrid}">
    <!-- 保留你原来的所有Setter -->
    <Setter Property="Foreground" Value="WhiteSmoke"/>
    <Setter Property="Background" Value="Transparent"/>
    <!-- ... 其他原有Setter ... -->
    
    <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"/>
                                    <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}"/>
                                    <ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Grid.Row="2" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
                                    
                                    <!-- 添加与列头同背景的矩形,填充滚动条顶部空白 -->
                                    <Rectangle Grid.Column="2" Grid.Row="0" Fill="#1a95d4" Height="{Binding ActualHeight, ElementName=PART_ColumnHeadersPresenter}"/>
                                </Grid>
                            </ControlTemplate>
                        </ScrollViewer.Template>
                        <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    </ScrollViewer>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这个模板里的Rectangle会自动匹配列头高度,完美填充滚动条顶部的空白区域,且不会影响原有交互。

方法2:外层套ScrollViewer(备选)

隐藏DataGrid默认滚动条,在外层套一个ScrollViewer:

<ScrollViewer VerticalScrollBarVisibility="Auto" Width="500" Margin="50 20">
    <DataGrid x:Name="DataGrid"
              ItemsSource="{Binding ProfilesDataGrid}"
              Style="{StaticResource DataGrid_Style}"
              CellStyle="{StaticResource DataGridCell_Style}"
              RowStyle="{StaticResource DataGridRow_Style}"
              RowHeaderStyle="{StaticResource DataGridRowHeader_Style}"
              ColumnHeaderStyle="{StaticResource DataGridColHeader_Style}"
              VerticalScrollBarVisibility="Hidden">
        <!-- 列定义不变 -->
    </DataGrid>
</ScrollViewer>

注意:这种方法会导致列头随滚动条移动,若需要固定列头,需额外实现列头固定逻辑。

关于ScrollContentPresenter方案无法使用的原因

你看到的ScrollContentPresenter方案,是直接手动替换DataGrid内部的内容容器,但当绑定ItemsSource时,DataGrid的ItemsPresenter是控件自动生成的,负责数据源绑定、行容器渲染。强行替换成自定义ScrollContentPresenter会破坏DataGrid的内部数据绑定逻辑,导致行无法正常显示,因此只适用于手动写死DataGrid内容的场景,不支持绑定ItemsSource的情况。

内容的提问来源于stack exchange,提问作者HandmadeWeakness

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 22:52:02