Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove left border grid line for WPF DataGrid header columns to match data grid lines

The border styles for header cells and data cells in a WPF 4.0 DataGrid are inconsistent.. Header cells have a border that includes a left vertical border line and a right vertical border line around the header text. Data grid text column data lines are styled such that only the right side has a vertical border line. The following sample image illustrates this (note that the grid line color has been changed to #D0D0D0):

enter image description here

Here is the same image zoomed in to show the inconsistency:

enter image description here

How do you change the grid headers (perhaps via a templates or styles) to remove the left border, so that the header vertical border lines line up with the data border lines?

like image 406
Michael Goldshteyn Avatar asked Mar 06 '11 21:03

Michael Goldshteyn


2 Answers

To avoid this just add below property setting in DataGridColumnHeader style.

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

The issue in this datagrid is the border drawing is happening inside header cell boundry on left side. This is causing the additional lining as shown in the picture above. If you also set datagrid's broderthickness then issue will appear on for top side of the cell also.

Hope this settings will solve problem when thickness is '1'. For other thicknesses you know now what you have to adjust :)

like image 78
umesh desai Avatar answered Oct 02 '22 01:10

umesh desai


Update: Added two solutions, both will produce result like

enter image description here

Solution 1

  • Set SeparatorVisibility="Collapsed" for DataGridHeaderBorder
  • Add Left and Right Separator as Borders
  • Handle Hover, Pressed and Sorted in Triggers
  • Add a reference to 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>

Solution 2

The Separators for DataGridColumnHeader is drawn in the RenderTheme method in DataGridHeaderBorder. This class is pretty much an "all or nothing" deal since changing any property in it will disable the entire style (no border, no sort-arrows etc.). It is also sealed so we can't derive from it. We can however copy the entire class and make the DataGridColumnHeaders use that class instead.

The part that draws the separators looks like this

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)));
            }

From here we could just remove the Left Separator and we would get a Separator Width of 1 instead of 2 but then we would get the wrong coloring for the left side when Hovering, Pressing or Sorting a column. To overcome this we can move the Left Separator by 1 to the Left and change the ZIndex so Hovering etc. gets higher ZIndex than normal coloring. For this to work we also need to bind ZIndex of DataGridColumnHeader to ZIndex of DataGridColumnBorder.

We can use it like this

<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 was to big to post so I uploaded it here: MyDataGridHeaderBorder.cs

like image 28
Fredrik Hedblad Avatar answered Oct 01 '22 23:10

Fredrik Hedblad