【问题标题】:Remove left border grid line for WPF DataGrid header columns to match data grid lines删除 WPF DataGrid 标题列的左边框网格线以匹配数据网格线
【发布时间】:2011-07-09 23:26:12
【问题描述】:

WPF 4.0 DataGrid 中标题单元格和数据单元格的边框样式不一致。标题单元格的边框包括标题文本周围的左垂直边框线和右垂直边框线。数据网格文本列数据线的样式设置为只有右侧有垂直边框线。以下示例图像说明了这一点(请注意,网格线颜色已更改为#D0D0D0):

这是同一张放大的图片以显示不一致:

如何更改网格标题(可能通过模板或样式)以移除左边框,使标题垂直边框线与数据边框线对齐?

【问题讨论】:

  • 一个更简单的解决方案是通过在两侧绘制分隔符将DataGridCell 的厚度“加倍”。也许这个问题可以提供帮助:stackoverflow.com/questions/4737518/…。否则,您基本上必须为DataGridColumnHeader 重新创建整个模板
  • 双粗边框在我看来是错误的,因为它们浪费了水平空间。我想让我所有的网格线、标题和数据都具有相同的宽度,一个单位。
  • 我完全同意,我自己也试过几次。问题是DataGridColumnHeader 的大部分部分都是在后面的代码中绘制的,一旦您更改任何内容,例如将背景设置为绿色,那么您就会失去整个样式。
  • 附带说明,RowHeaders 有同样的问题
  • @Meleak(RE:行标题),它看起来不是那样的。在我放大的图像中,行标题总是一个单位厚。

标签: wpf wpf-controls wpfdatagrid


【解决方案1】:

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

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

【讨论】:

  • 这个修改了整个标题周围的边框,而不是单个标题单元格。
【解决方案2】:

为避免这种情况,只需在 DataGridColumnHeader 样式中添加以下属性设置。

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

此数据网格中的问题是边框绘制发生在左侧标题单元格边界内。如上图所示,这导致了额外的衬里。如果您还设置了数据网格的 broderthickness,那么问题也会出现在单元格的顶部。

希望此设置能解决厚度为“1”时的问题。对于其他厚度,您现在知道需要调整什么了:)

【讨论】:

    【解决方案3】:

    更新:添加了两个解决方案,两者都会产生类似的结果

    解决方案 1

    • SeparatorVisibility="Collapsed" 设置为DataGridHeaderBorder
    • 将左右分隔符添加为Borders
    • 在触发器中处理悬停按下排序
    • 添加对 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 方法中绘制的。此类几乎是“全有或全无”交易,因为更改其中的任何属性都会禁用整个样式(无边框,无排序箭头等)。它也是密封的,所以我们不能从中得到。然而,我们可以复制整个类并让DataGridColumnHeaders 使用该类。

    绘制分隔符的部分是这样的

    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,以便 Hovering 等获得比正常着色更高的 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

    【讨论】:

    • 哇,我没有意识到仅仅改变一些线条的粗细会这么复杂。
    • @Michael Goldshteyn:确实不应该。问题是它们是在后面的代码中绘制的,正如您在我的帖子中看到的那样,宽度是静态 1.0。如果有一种更简单的方法,我永远找不到它:) 我一直在使用的解决方案是第二种。我在写答案的时候想出了第一个,所以我把它们都加了
    猜你喜欢
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2014-01-14
    • 1970-01-01
    • 2011-06-15
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多