将WPF DataGrid标题列的左边框网格线去除以匹配数据网格线

10
WPF 4.0 DataGrid中的头部单元格和数据单元格的边框样式不一致。头部单元格的边框包括围绕头部文本的左竖直边框线和右竖直边框线。数据网格文本列数据行的样式只有右侧有竖直边框线。下面示例图像说明了这一点(请注意,网格线颜色已更改为#D0D0D0): enter image description here 以下是放大后显示不一致的同一图像: enter image description here 如何更改网格标题(可能通过模板或样式)以删除左边框,使得标题竖直边框线与数据边框线对齐?

一种更简单的解决方案是通过在 DataGridCell 的两侧绘制分隔符来“加倍厚度”。也许这个问题可以帮到你:http://stackoverflow.com/questions/4737518/special-gridline-style-for-only-one-column。否则,你基本上需要重新创建整个 DataGridColumnHeader 模板。 - Fredrik Hedblad
双倍粗边框在我看来显得不太对,因为它们浪费了水平空间。我想让我的所有网格线、标题和数据都具有相同的宽度,即一个单位。 - Michael Goldshteyn
顺便提一下,行标题也有同样的问题。 - Fredrik Hedblad
@Meleak(关于行标题),看起来并不是这样。在我的放大图像中,行标题始终只有一个单位的厚度。 - Michael Goldshteyn
@Meleak,我从我的示例中删除了行标题,但我理解你的观点。 - Michael Goldshteyn
显示剩余2条评论
3个回答

20

为避免此问题,只需在DataGridColumnHeader样式中添加以下属性设置。

<Setter Property="BorderThickness" Value="1" />
<Setter Property="Margin" Value="-1,-1,0,0" />

这个datagrid的问题在于边框绘制发生在左侧标题单元格边界内部。这会导致额外的线条,如上图所示。如果你还设置了datagrid的边框厚度,则问题也会出现在单元格顶部。

希望这些设置可以解决当厚度为'1'时的问题。对于其他厚度,你现在知道该如何调整了 :)


5

更新:添加了两个解决方案,都将产生如下所示的结果

enter image description here

解决方案1

  • DataGridHeaderBorder 设置 SeparatorVisibility="Collapsed"
  • 添加左右分隔符作为 Border
  • 在触发器中处理悬停按下排序
  • 添加对 PresentationFramework.Aero 的引用

Xaml

<DataGrid ...>
    <DataGrid.ColumnHeaderStyle>
       <Style TargetType="{x:Type DataGridColumnHeader}"
              xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero">
            <Style.Resources>
                <Style x:Key="ColumnHeaderGripperStyle" TargetType="{x:Type Thumb}">
                    <Setter Property="Width" Value="8"/>
                    <Setter Property="Background" Value="Transparent"/>
                    <Setter Property="Cursor" Value="SizeWE"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type Thumb}">
                                <Border Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"/>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
                <LinearGradientBrush x:Key="normalBrush" StartPoint="0,0" EndPoint="0,1">
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Color="#FFF2F2F2" Offset="0" />
                        <GradientStop Color="#FFEFEFEF" Offset="0.4" />
                        <GradientStop Color="#FFE7E8EA" Offset="0.4" />
                        <GradientStop Color="#FFDEDFE1" Offset="1" />
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
                <LinearGradientBrush x:Key="pressedBrush" StartPoint="0,0" EndPoint="0,1">
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Color="#FF7A9EB1" Offset="0" />
                        <GradientStop Color="#FF7A9EB1" Offset="0.4" />
                        <GradientStop Color="#FF5091AF" Offset="0.4" />
                        <GradientStop Color="#FF4D8DAD" Offset="1" />
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
                <LinearGradientBrush x:Key="hoveredBrush" StartPoint="0,0" EndPoint="0,1">
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Color="#FF88CBEB" Offset="0" />
                        <GradientStop Color="#FF88CBEB" Offset="0.4" />
                        <GradientStop Color="#FF69BBE3" Offset="0.4" />
                        <GradientStop Color="#FF69BBE3" Offset="1" />
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
                <SolidColorBrush x:Key="sortedBrush" Color="#FF96D9F9"/>
            </Style.Resources>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <Border x:Name="separatorLeft" Grid.Column="0" Width="1" HorizontalAlignment="Left"
                                    Background="{StaticResource normalBrush}">
                                <Border.RenderTransform>
                                    <TranslateTransform X="-1"/>
                                </Border.RenderTransform>
                            </Border>
                            <Microsoft_Windows_Themes:DataGridHeaderBorder x:Name="headerBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" IsClickable="{TemplateBinding CanUserSort}" IsPressed="{TemplateBinding IsPressed}" IsHovered="{TemplateBinding IsMouseOver}" Padding="{TemplateBinding Padding}" SortDirection="{TemplateBinding SortDirection}" SeparatorBrush="{TemplateBinding SeparatorBrush}"
                                                                            SeparatorVisibility="Collapsed">
                                <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Microsoft_Windows_Themes:DataGridHeaderBorder>
                            <Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" Style="{StaticResource ColumnHeaderGripperStyle}"/>
                            <Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Style="{StaticResource ColumnHeaderGripperStyle}"/>
                            <Border x:Name="separatorRight" Grid.Column="1" Width="1" Background="{StaticResource normalBrush}"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter TargetName="separatorRight" Property="Background" Value="{StaticResource pressedBrush}"/>
                                <Setter TargetName="separatorLeft" Property="Background" Value="{StaticResource pressedBrush}"/>
                                <Setter Property="Panel.ZIndex" Value="2"/>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="separatorRight" Property="Background" Value="{StaticResource hoveredBrush}"/>
                                <Setter TargetName="separatorLeft" Property="Background" Value="{StaticResource hoveredBrush}"/>
                                <Setter Property="Panel.ZIndex" Value="2"/>
                            </Trigger>
                            <Trigger Property="SortDirection" Value="Ascending">
                                <Setter TargetName="separatorRight" Property="Background" Value="{StaticResource sortedBrush}"/>
                                <Setter TargetName="separatorLeft" Property="Background" Value="{StaticResource sortedBrush}"/>
                                <Setter Property="Panel.ZIndex" Value="2"/>
                            </Trigger>
                            <Trigger Property="SortDirection" Value="Descending">
                                <Setter TargetName="separatorRight" Property="Background" Value="{StaticResource sortedBrush}"/>
                                <Setter TargetName="separatorLeft" Property="Background" Value="{StaticResource sortedBrush}"/>
                                <Setter Property="Panel.ZIndex" Value="2"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGrid.ColumnHeaderStyle>
    <!--...-->
</DataGrid>

解决方案2

DataGridColumnHeader的分隔符是在DataGridHeaderBorderRenderTheme方法中绘制的。这个类基本上是一个“全有或全无”的东西,因为更改其中任何属性都将禁用整个样式(没有边框、没有排序箭头等)。它也是密封的,所以我们不能从中派生。但是,我们可以复制整个类并使DataGridColumnHeader使用该类。

绘制分隔符的部分如下:

private void RenderTheme(DrawingContext dc)
{
    // ...
            if (this.SeparatorVisibility == Visibility.Visible)
            {
                // ...
                // Draw Left Separator
                dc.DrawRectangle(separatorBrush, null, new Rect(0, 0.0, 1.0, Max0(renderSize.Height - 0.95)));
                // Draw Right Separator
                dc.DrawRectangle(separatorBrush, null, new Rect(renderSize.Width - 1.0, 0.0, 1.0, Max0(renderSize.Height - 0.95)));
            }

从这里开始,我们可以只删除左分隔符,这样我们将得到一个分隔符宽度为1而不是2,但是当悬停按下排序列时,左侧的颜色会出现错误。为了克服这个问题,我们可以将左分隔符向左移动1个单位,并改变ZIndex,使悬停等操作的ZIndex高于普通着色。为了使其正常工作,我们还需要将DataGridColumnHeader的ZIndex绑定到DataGridColumnBorder的ZIndex。

我们可以像这样使用它

<DataGrid ...>
    <DataGrid.ColumnHeaderStyle>
        <Style TargetType="{x:Type DataGridColumnHeader}">
            <Style.Resources>
                <Style x:Key="ColumnHeaderGripperStyle" TargetType="{x:Type Thumb}">
                    <Setter Property="Width" Value="8"/>
                    <Setter Property="Background" Value="Transparent"/>
                    <Setter Property="Cursor" Value="SizeWE"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type Thumb}">
                                <Border Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"/>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Style.Resources>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
                        <Grid>
                            <local:MyDataGridHeaderBorder Panel.ZIndex="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridColumnHeader}}, Path=(Panel.ZIndex), Mode=TwoWay}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" IsClickable="{TemplateBinding CanUserSort}" IsPressed="{TemplateBinding IsPressed}" IsHovered="{TemplateBinding IsMouseOver}" Padding="{TemplateBinding Padding}" SortDirection="{TemplateBinding SortDirection}" SeparatorBrush="{TemplateBinding SeparatorBrush}" SeparatorVisibility="{TemplateBinding SeparatorVisibility}">
                                <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </local:MyDataGridHeaderBorder>
                            <Thumb x:Name="PART_LeftHeaderGripper" Panel.ZIndex="4" HorizontalAlignment="Left" Style="{StaticResource ColumnHeaderGripperStyle}"/>
                            <Thumb x:Name="PART_RightHeaderGripper" Panel.ZIndex="4" HorizontalAlignment="Right" Style="{StaticResource ColumnHeaderGripperStyle}"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGrid.ColumnHeaderStyle>
    <!--...-->
</DataGrid>

MyDataGridHeaderBorder 太大了,无法发布,所以我在这里上传了它:MyDataGridHeaderBorder.cs


3
哇,我没有意识到仅仅改变一些线条的厚度会这么复杂。 - Michael Goldshteyn
@Michael Goldshteyn:好的,实际上不应该有这个问题。问题在于它们是在代码后台中绘制出来的,并且正如您在我的帖子中所看到的,宽度是静态的1.0。如果有更简单的方法,我从来没有找到过 :) 我一直在使用的解决方案是第二种。我现在想到了第一种方法,因此我将它们都添加了进来。 - Fredrik Hedblad

-1

只需将HeaderStyle中的左边框厚度设置为0:

<Style x:Key="HeaderStyle" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="BorderThickness" Value="0,1,1,1"></Setter>
</Style>

这个修改的是整个标题周围的边框,而不是单个标题单元格。 - Gábor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接