Introduction
I was recently asked by one of my friends whether we can have solid gridlines in Grid control in WPF. I tried to find some answers online, but none of them were very relevant. So I wrote down a custom grid control with many features included, the one feature which was required.
Background
The problem presented above has many alternate solutions. We can create a border inside every cell and represent it as an alternative to the above solution. But this is not the exact solution.
On MSDN, somewhere I found this. MSDN docs say "Only dotted lines are available because this property is intended as a design tool to debug layout problems and is not intended for use in production quality code. If you want lines inside a Grid
, style the elements within the Grid
to have borders." See Here[^]
Even the source code of Grid
in WPF depicts something similar to the above.
So, I created some example which fulfill the above requirement.
Using the Code
This enum
is used to set the visibility of grid lines which can be either Both Side, Horizontal, Vertical or no gridlines
(no GridLines
is of no use actually :)).
public enum GridLinesVisibilityEnum
{
Both,
Vertical,
Horizontal,
None
}
We have a boolean DependencyProperty
called ShowCustomGridLines
which sets the visibility of Solid GridLines
.
public bool ShowCustomGridLines
{
get { return (bool)GetValue(ShowCustomGridLinesProperty); }
set { SetValue(ShowCustomGridLinesProperty, value); }
}
public static readonly DependencyProperty ShowCustomGridLinesProperty =
DependencyProperty.Register("ShowCustomGridLines",
typeof(bool), typeof(CustomGrid), new UIPropertyMetadata(false));
We have next DependencyProperty
of type GridLinesVisibilityEnum
called GridLinesVisibility
which sets the visibility of GridLines
.
public bool ShowCustomGridLines
{
get { return (bool)GetValue(ShowCustomGridLinesProperty); }
set { SetValue(ShowCustomGridLinesProperty, value); }
}
public static readonly DependencyProperty ShowCustomGridLinesProperty =
DependencyProperty.Register("ShowCustomGridLines",
typeof(bool), typeof(CustomGrid), new UIPropertyMetadata(false));
We have next DependencyProperty
of type Brush
called GridLineBrush
which sets the color of GridLines
Border.
public Brush GridLineBrush
{
get { return (Brush)GetValue(GridLineBrushProperty); }
set { SetValue(GridLineBrushProperty, value); }
}
public static readonly DependencyProperty GridLineBrushProperty =
DependencyProperty.Register("GridLineBrush",
typeof(Brush), typeof(CustomGrid), new UIPropertyMetadata(Brushes.Black));
We have next DependencyProperty
of type double
called GridLineThickness
which sets the Thickness of GridLines
Border.
public double GridLineThickness
{
get { return (double)GetValue(GridLineThicknessProperty); }
set { SetValue(GridLineThicknessProperty, value); }
}
public static readonly DependencyProperty GridLineThicknessProperty =
DependencyProperty.Register("GridLineThickness",
typeof(double), typeof(CustomGrid), new UIPropertyMetadata(1.0));
Finally, we are overriding the OnRender()
method to draw the GridLines
.
if (ShowCustomGridLines)
{
if (GridLinesVisibility == GridLinesVisibilityEnum.Both)
{
foreach (var rowDefinition in RowDefinitions)
{
dc.DrawLine(new Pen(GridLineBrush, GridLineThickness),
new Point(0, rowDefinition.Offset),
new Point(ActualWidth, rowDefinition.Offset));
}
foreach (var columnDefinition in ColumnDefinitions)
{
dc.DrawLine(new Pen(GridLineBrush, GridLineThickness),
new Point(columnDefinition.Offset, 0),
new Point(columnDefinition.Offset, ActualHeight));
}
dc.DrawRectangle(Brushes.Transparent,
new Pen(GridLineBrush, GridLineThickness),
new Rect(0, 0, ActualWidth, ActualHeight));
}
else if (GridLinesVisibility == GridLinesVisibilityEnum.Vertical)
{
foreach (var columnDefinition in ColumnDefinitions)
{
dc.DrawLine(new Pen(GridLineBrush, GridLineThickness),
new Point(columnDefinition.Offset, 0),
new Point(columnDefinition.Offset, ActualHeight));
}
dc.DrawRectangle(Brushes.Transparent,
new Pen(GridLineBrush, GridLineThickness),
new Rect(0, 0, ActualWidth, ActualHeight));
}
else if (GridLinesVisibility == GridLinesVisibilityEnum.Horizontal)
{
foreach (var rowDefinition in RowDefinitions)
{
dc.DrawLine(new Pen(GridLineBrush, GridLineThickness),
new Point(0, rowDefinition.Offset),
new Point(ActualWidth, rowDefinition.Offset));
}
dc.DrawRectangle(Brushes.Transparent,
new Pen(GridLineBrush, GridLineThickness),
new Rect(0, 0, ActualWidth, ActualHeight));
}
else if (GridLinesVisibility == GridLinesVisibilityEnum.Horizontal)
{
}
}
base.OnRender(dc);
So finally, the full set of the custom class looks something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace GridWithSolidGridLines
{
public class CustomGrid : Grid
{
#region GridLinesVisibilityEnum
public enum GridLinesVisibilityEnum
{
Both,
Vertical,
Horizontal,
None
}
#endregion
#region Properties
public bool ShowCustomGridLines
{
get { return (bool)GetValue(ShowCustomGridLinesProperty); }
set { SetValue(ShowCustomGridLinesProperty, value); }
}
public static readonly DependencyProperty ShowCustomGridLinesProperty =
DependencyProperty.Register("ShowCustomGridLines", typeof(bool),
typeof(CustomGrid), new UIPropertyMetadata(false));
public GridLinesVisibilityEnum GridLinesVisibility
{
get { return (GridLinesVisibilityEnum)GetValue(GridLinesVisibilityProperty); }
set { SetValue(GridLinesVisibilityProperty, value); }
}
public static readonly DependencyProperty GridLinesVisibilityProperty =
DependencyProperty.Register("GridLinesVisibility",
typeof(GridLinesVisibilityEnum), typeof(CustomGrid),
new UIPropertyMetadata(GridLinesVisibilityEnum.Both));
public Brush GridLineBrush
{
get { return (Brush)GetValue(GridLineBrushProperty); }
set { SetValue(GridLineBrushProperty, value); }
}
public static readonly DependencyProperty GridLineBrushProperty =
DependencyProperty.Register("GridLineBrush", typeof(Brush),
typeof(CustomGrid), new UIPropertyMetadata(Brushes.Black));
public double GridLineThickness
{
get { return (double)GetValue(GridLineThicknessProperty); }
set { SetValue(GridLineThicknessProperty, value); }
}
public static readonly DependencyProperty GridLineThicknessProperty =
DependencyProperty.Register("GridLineThickness", typeof(double),
typeof(CustomGrid), new UIPropertyMetadata(1.0));
#endregion
protected override void OnRender(DrawingContext dc)
{
if (ShowCustomGridLines)
{
if (GridLinesVisibility == GridLinesVisibilityEnum.Both)
{
foreach (var rowDefinition in RowDefinitions)
{
dc.DrawLine(new Pen(GridLineBrush, GridLineThickness),
new Point(0, rowDefinition.Offset),
new Point(ActualWidth, rowDefinition.Offset));
}
foreach (var columnDefinition in ColumnDefinitions)
{
dc.DrawLine(new Pen(GridLineBrush, GridLineThickness),
new Point(columnDefinition.Offset, 0),
new Point(columnDefinition.Offset, ActualHeight));
}
dc.DrawRectangle(Brushes.Transparent,
new Pen(GridLineBrush, GridLineThickness),
new Rect(0, 0, ActualWidth, ActualHeight));
}
else if (GridLinesVisibility == GridLinesVisibilityEnum.Vertical)
{
foreach (var columnDefinition in ColumnDefinitions)
{
dc.DrawLine(new Pen(GridLineBrush, GridLineThickness),
new Point(columnDefinition.Offset, 0),
new Point(columnDefinition.Offset, ActualHeight));
}
dc.DrawRectangle(Brushes.Transparent,
new Pen(GridLineBrush, GridLineThickness),
new Rect(0, 0, ActualWidth, ActualHeight));
}
else if (GridLinesVisibility == GridLinesVisibilityEnum.Horizontal)
{
foreach (var rowDefinition in RowDefinitions)
{
dc.DrawLine(new Pen(GridLineBrush, GridLineThickness),
new Point(0, rowDefinition.Offset),
new Point(ActualWidth, rowDefinition.Offset));
}
dc.DrawRectangle(Brushes.Transparent,
new Pen(GridLineBrush, GridLineThickness),
new Rect(0, 0, ActualWidth, ActualHeight));
}
else if (GridLinesVisibility == GridLinesVisibilityEnum.Horizontal)
{
}
}
base.OnRender(dc);
}
static CustomGrid()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomGrid),
new FrameworkPropertyMetadata(typeof(CustomGrid)));
}
}
}
Now finally, we can use this custom control in our XAML and create a grid control with solid gridlines and color and thickness of our choice.
<Window x:Class="GridWithSolidGridLines.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:customGrid="clr-namespace:GridWithSolidGridLines"
Title="MainWindow" Height="350" Width="525">
<customGrid:CustomGrid ShowCustomGridLines="True"
GridLineBrush="DodgerBlue" GridLineThickness="2">
<customGrid:CustomGrid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</customGrid:CustomGrid.RowDefinitions>
<customGrid:CustomGrid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</customGrid:CustomGrid.ColumnDefinitions>
</customGrid:CustomGrid>
</Window>
The above XAML code will produce something like below. In the below image, the grid has solid blue gridlines with gridlines on both sides, horizontal and vertical because the GridLinesVisibility
is by default set to Both
.
If we want to have only horizontal gridlines, we can set the GridLinesVisibility
property to Horizontal
and it will produce result something like this.
Similarly, we can set the GridLinesVisibility
property to Vertical
and it will produce a result something like below:
That's all. Thanks for giving your time to read my post.
Hope it helps someone. I have attached the source code as well.