如何修复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
相关产品推荐
相关产品推荐

