1
votes

Is there any way to show gridlines on a multiline textbox or a richtextbox? Perhaps by overriding the OnPaint event?

I am using the textbox to insert address information, for each line it would be something like:

Street
City
Country
etc.

I am using WinForms with C#.

3
Why do you need gridlines in a textbox? A textbox is not a grid. - Bauss
Just to make it look a bit nicer. - langjacques
Not likely. Given the nature of those controls, I doubt any level of override is going to work. They're stubborn. You'd probably have to invent a new control ground-up. - DonBoitnott
You can make a work around for this scenario like Take 3 text boxes and each text box Y location should immediately begin with Y axis of previous box+2 and make all the text boxes border style to none. and draw a rectangle using Graphics Calss and draw a line between text boxes in OnPaint - bhanu.cs
@BhanuChowdary - That could work yes but I wont be able to copy the text in one shot from all 3 textboxes - I would like to keep it one textbox - langjacques

3 Answers

3
votes

You can do it using one of these methods:

  • Customize Paint of TextBox
  • Using RTF Tricks

and here is a screenshot of these 2 ways:

enter image description here

I recommend using first method if you really want this feature.

1- Customizing Paint of TextBox


Customizing textbox paint in not straightforward. You can customize paint of TextBox in different ways. here is 2 way of customize painting of TextBox.

1-1 Customizing Paint of TextBox using NativeWindow


In this way should subclass a TextBox using NativeWindow and handle WM_PAINT in window procedure. Here is a complete code listing that implements what you need.

To use code it is enough to pass your textbox to an instance of CustomPaintTextBox:

var t = new CustomControls.CustomPaintTextBox(this.textBox1);

And here is the code of CustomPaintTextBox

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace CustomControls
{
    public class CustomPaintTextBox : NativeWindow
    {
        private TextBox parentTextBox;
        private const int WM_PAINT = 15;
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_PAINT: 
                    // invalidate textbox to make it refresh
                    parentTextBox.Invalidate();
                    // call default paint
                    base.WndProc(ref m);
                    // draw custom paint
                    this.CustomPaint();
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }
        public CustomPaintTextBox(TextBox textBox)
        {
            this.parentTextBox = textBox;
            textBox.TextChanged += textBox_TextChanged;
            // subscribe for messages
            this.AssignHandle(textBox.Handle);
        }
        void textBox_TextChanged(object sender, EventArgs e)
        {
            CustomPaint();
        }
        private void CustomPaint()
        {
            var g= this.parentTextBox.CreateGraphics();
            float y = 0;
            var lineHeight = g.MeasureString("X", this.parentTextBox.Font).Height;
            while (y < this.parentTextBox.Height)
            {
                y += lineHeight;
                g.DrawLine(Pens.Red, 0f, y, (float)this.parentTextBox.Width, y);
            }
        }
    }
}

The up side of this solution is its is quiet simple and doesn't need new inherited textbox.

1-2- Creating Transparent TextBox


This way you should first Make a transparent text box and then set the background of it to your gridlines that you want. Since this way is also a way of creating custom paint textbox, you can customize the painting of that textbox too and bend it to your will.

Here is link to 2 greate articles that cover Transparent TextBox and Transparent RichTextBox:

2- Using RTF tricks


There is some rtf tricks than you ca use to show grid lines in RichTextBox. One of best tricks is using tables in RTF. In below code We used 3 rows that contains a cell of width 2000 twips:

this.richTextBox1.SelectAll();
this.richTextBox1.SelectedRtf =
@"{\rtf1\ansi\deff0
{\trowd
\cellx2000
\intbl Street\cell
\row}
{\trowd
\cellx2000
\intbl City\cell
\row}
{\trowd
\cellx2000
\intbl Country\cell
\row}
}";

Important: When pasting above code in code editor, be careful to put no indents before richtext characters. If Visual studio inserted indent before them, you remove all indents.

0
votes

Start with this code:

class GridLineTextBox : TextBox
{
    public GridLineTextBox()
    {
        SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        var y = 0f;
        var lineHeight = e.Graphics.MeasureString("W", Font).Height;
        while (y < e.ClipRectangle.Height)
        {
            y += lineHeight;
            e.Graphics.DrawLine(System.Drawing.Pens.Aqua, new PointF(0, y), new PointF(e.ClipRectangle.Width, y));
        }
    }
}
0
votes

Maybe an RTF template file:

{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 Calibri;}}
{\trowd \trgaph180
\cellx3440\pard\intbl [0]\cell
\row
\trowd \trgaph180
\cellx3440\pard\intbl [1]\cell
\row
\trowd \trgaph180
\cellx3440\pard\intbl [2]\cell
\row
\para}

Dim fileContents As String
fileContents = My.Computer.FileSystem.ReadAllText("C:\temp\template.rtf")
Dim sRTF As String = fileContents.Replace("[0]", "line 1").Replace("[1]", "line 2").Replace("[2]", "line 3")
RichTextBox1.Rtf = sRTF