2

I want to draw a margin line at 80 characters in a WinForms TextBox. Here is what I've tried, in my TextBox subclass:

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);

    const int WM_PAINT = 0x00F;
    if (m.Msg == WM_PAINT) {
        DrawMargin();
    }
}

void DrawMargin()
{
    using (Pen pen = new Pen(Color.Gray, 1)) {
        using (Graphics graphics = CreateGraphics()) {
            float charWidth = graphics.MeasureString("M", Font).Width;
            graphics.DrawLine(pen, charWidth * 80, 0, charWidth * 80, Height);
        }
    }
}

There are at least three problems with this:

  1. When the user enters some text, part of the line gets blanked out (goes white).
  2. When the user selects some text with the mouse, the above happens again.
  3. The line flickers when the TextBox is scrolled.

I notice that TED Notepad (which uses a Win32 EDIT control) is able to draw a margin without any problems, so it seems that it's possible to do what I want. Could anyone advise me how?

Tom
  • 817
  • 7
  • 14
  • Pretty big trick. EDIT draws without using WM_PAINT, a crime committed when Windows 2 had to run on a 386SUX processor. Erasing your line in the process. You'll have to ask Ted how he did it. – Hans Passant Sep 08 '11 at 13:33
  • Thanks, I'll try asking him/her. – Tom Sep 08 '11 at 13:55

2 Answers2

1

I am not sure about this method. But one thing you could look at trying is inserting an image into the text box. The image would of course be your margin, and the text would automatically start after the picture. To include a picture inside a text box see How can I insert an image into a RichTextBox?

Edit: I have also found this article http://www.codedblog.com/2007/09/17/owner-drawing-a-windowsforms-textbox/ which seems to facilitate painting in the background of a text box. The methods described here seems to take you a long way towards what you require.

Hope this helps.

Community
  • 1
  • 1
MoonKnight
  • 23,214
  • 40
  • 145
  • 277
1

As far as I can tell, the best way of doing this is simply to place a WinForms.Panel over the TextBox:

class FooTextBox : TextBox
{
    public FooTextBox()
    {
        margin = new Panel();

        margin.Enabled   = false;
        margin.BackColor = Color.LightGray;
        margin.Top       = 0;
        margin.Height    = ClientSize.Height;
        margin.Left      = <whatever>;
        margin.Width     = 1;

        Controls.Add(margin);
    }

    Panel margin;
}

Since the panel is not Enabled, it doesn't take mouse input.

Tom
  • 817
  • 7
  • 14