在使用自定义列头样式时,WPF DataGrid的列会错位一个像素
我有一个包含五列的DataGrid。当我在这个DataGrid上应用一个特定的ColumnHeaderStyle时,某些列似乎向右错位了一个像素。分隔这些列的垂直线似乎有时宽出一个像素、有时窄出一个像素,我在尝试弄清楚造成这种现象的原因。
这就是DataGrid。我当前隐藏了最右边的列,效果在“Example 3”和“Example 4”列之间清晰可见。
<DataGrid Grid.Row="4"
ItemsSource="{Binding ConditionTypeParameters}"
IsReadOnly="True"
AutoGenerateColumns="False"
Margin="0,20,0,10"
ColumnHeaderStyle="{StaticResource TableHeader}"
CanUserResizeColumns="False"
CanUserResizeRows="False"
CanUserSortColumns="False"
RowHeaderWidth="0"
MinRowHeight="40"
SelectionMode="Single"
SelectionUnit="Cell"
SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}">
<DataGrid.Columns>
<DataGridTextColumn Width="Auto"
Foreground="White"
CanUserReorder="False"
CanUserSort="False">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Example 1" />
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
<DataGridTextColumn Width="*"
CanUserReorder="False"
CanUserSort="False">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Example 2" />
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
<DataGridTextColumn Width="*"
CanUserReorder="False"
CanUserSort="False">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Example 3" />
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
<DataGridTextColumn Width="*"
Visibility="{x:Static Visibility.Visible}"
CanUserReorder="False"
CanUserSort="False">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Example 4" />
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
<DataGridTextColumn Width="*"
Visibility="{x:Static Visibility.Collapsed}"
CanUserReorder="False"
CanUserSort="False">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Example 5" />
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
第三列和第四列之间有一条白线分隔,第四列中被选中的单元格让这个问题更加明显。

将ColumnHeaderStyle从DataGrid中移除后,问题似乎就消失了。以下是应用的样式:
<Style x:Key="TableHeader"
TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Border x:Name="BackgroundBorder"
BorderThickness="1"
BorderBrush="#DBDBDB"
Padding="2"
Background="Red">
<ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
应用该样式时,即使第四列可见也会出现这个问题。在这种情况下,第三列和第四列表头之间的分界线明显更细。被选中的单元格的左边边框也更细。
第三列和第四列之间的分隔变得更薄,这种效果在所选单元格上也能看到。

将BorderThickness设为0并去除样式中的填充并不能解决问题:

没有边框时,白线会更加明显。把Margin和Padding都设为0,得到的结果也是一样的。
在寻求解决方案的过程中,我看到一篇描述看起来类似问题的帖子。列之间会出现一条白色竖线,但很遗憾,帖子中的推荐方案并不适用于我的情况,因为我需要对同一行上的单元格应用不同的背景色(上面的最小示例中没有展示)。此外,我也不认为该推荐方案解决了问题的根本原因:
是我的样式引起这个问题吗?造成这种行为的原因是什么?
解决方案
Gerry Schmitz的评论把我引向了正确的方向:问题其实是对齐问题。
父级布局Grid包含一个隐式宽度为*的列,由于项目需要,窗口大小是固定的。根据可用宽度,分配给DataGrid的空间可能引入一个像素的偏移。这导致某些列分隔符看起来比其他的更薄或更厚。
ColumnHeaderStyle让问题更加明显,但它并非根本原因。
新增一个宽度设为Auto的新父级Grid即可消除那条不希望出现的白线:

在我的情况下,这些单元格大多保持为空,因此我在用Width="*"定义的DataGridTextColumn上设置了MinWidth,以便让DataGrid在需要时能扩展。
以下是最终的布局:
<Grid Grid.Row="4"
HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<DataGrid Grid.Column="0"
ItemsSource="{Binding ConditionTypeParameters}"
IsReadOnly="True"
AutoGenerateColumns="False"
Margin="0,20,0,10"
ColumnHeaderStyle="{StaticResource TableHeader}"
CanUserResizeColumns="False"
CanUserResizeRows="False"
CanUserSortColumns="False"
RowHeaderWidth="0"
MinRowHeight="40"
SelectionMode="Single"
SelectionUnit="Cell"
SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}">
<DataGrid.Columns>
<DataGridTextColumn Width="Auto"
Foreground="White"
CanUserReorder="False"
CanUserSort="False">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Example 1" />
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
<DataGridTextColumn Width="*"
MinWidth="150"
CanUserReorder="False"
CanUserSort="False">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Example 2" />
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
<DataGridTextColumn Width="*"
MinWidth="150"
CanUserReorder="False"
CanUserSort="False">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Example 3" />
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
<DataGridTextColumn Width="*"
MinWidth="150"
Visibility="{x:Static Visibility.Visible}"
CanUserReorder="False"
CanUserSort="False">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Example 4" />
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
<DataGridTextColumn Width="*"
MinWidth="150"
Visibility="{x:Static Visibility.Visible}"
CanUserReorder="False"
CanUserSort="False">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Example 5" />
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>