Click here to Skip to main content
15,888,527 members
Articles / Desktop Programming / WPF
Tip/Trick

WPF Grid Control with Solid GridLines

Rate me:
Please Sign up or sign in to vote.
3.81/5 (10 votes)
14 Oct 2015CPOL2 min read 44.3K   918   7   6
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.

Image 1

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 :)).

C#
public enum GridLinesVisibilityEnum
       {
           Both,
           Vertical,
           Horizontal,
           None
       }

We have a boolean DependencyProperty called ShowCustomGridLines which sets the visibility of Solid GridLines.

C#
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.

C#
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.

C#
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.

C#
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.

C#
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:

C#
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.

XML
<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.

Image 2

If we want to have only horizontal gridlines, we can set the GridLinesVisibility property to Horizontal and it will produce result something like this.

Image 3

Similarly, we can set the GridLinesVisibility property to Vertical and it will produce a result something like below:

Image 4

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Comments and Discussions

 
GeneralMy vote of 5 Pin
danwizard20817-Dec-19 6:16
danwizard20817-Dec-19 6:16 
GeneralMy vote of 5 Pin
gbrandt14-Apr-19 2:35
gbrandt14-Apr-19 2:35 
SuggestionSome improvements Pin
Member 36441814-Apr-18 21:55
Member 36441814-Apr-18 21:55 
GeneralRe: Some improvements Pin
danwizard20817-Dec-19 6:14
danwizard20817-Dec-19 6:14 
SuggestionRedraw error with share size group Pin
Member 1129870623-Sep-16 10:03
Member 1129870623-Sep-16 10:03 
QuestionAbout the snippets Pin
Nelek14-Oct-15 22:46
protectorNelek14-Oct-15 22:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.