Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WPF Grid Control with Solid GridLines

0.00/5 (No votes)
14 Oct 2015 1  
This is a simple tip to describe how to create a custom grid control which has solid gridlines with choice to change the gridlines brush, thickness and GridLinesVisibility.

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here