8

This code automatically sizes a RichTextBox according to it's contents. I'm having issues, especially with tables. \t may be ignored. I tried a managed solution, now I'm trying platform invoke. Current Output:

enter image description here

    [DllImport("gdi32.dll")]
    static extern bool GetTextExtentPoint32(IntPtr hdc, string lpString, int cbString, out SIZE lpSize);

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr GetDC(IntPtr hWnd);

    [StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct SIZE
    {
        public int cx;
        public int cy;

        public SIZE(int cx, int cy)
        {
            this.cx = cx;
            this.cy = cy;
        }
    }

    public static void Main()
    {
        Form form = new Form();
        RichTextBox rtfBox = new RichTextBox();

        rtfBox.Rtf = @"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil Arial;}}\viewkind4\uc1\trowd\trgaph100\cellx1000\cellx2000\pard\intbl\lang1033\f0\fs20  hi\cell  bye\cell\row\intbl  one\cell  two\cell\row\pard\par}";
        rtfBox.ScrollBars = RichTextBoxScrollBars.None;

        string sInput = "hi\t bye\t\n";// one\t two\t\n";
        SIZE CharSize;

        form.Controls.Add(rtfBox);

        IntPtr hdc = GetDC(IntPtr.Zero);//Context for entire screen
        GetTextExtentPoint32(hdc, sInput, sInput.Length, out CharSize);

        rtfBox.Width = CharSize.cx;
        rtfBox.Height = CharSize.cy;

        form.Visible = false;

        form.ShowDialog();
    }

(Note, for simplicity this is a console application with a reference to System.Windows.Forms.dll)

P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348

3 Answers3

14

Have you looked at the ContentsResized event? Add the following method to be called when the event fires:

private void richTextBox_ContentsResized(object sender, ContentsResizedEventArgs e)
{
    var richTextBox = (RichTextBox) sender;
    richTextBox.Width = e.NewRectangle.Width;
    richTextBox.Height = e.NewRectangle.Height;
}

When the RTF content is changed (using Rtf), the RichTextBox should be resized to match its contents. Make sure you also set the WordWrap property to false.


I've tried it with your table example and it does appear to work (albeit with a little offset, which you could possibly solve by adding a few pixels of width to the adjusted size - not sure why that happens):

P.Brian.Mackey EDIT
This answer worked for me. To clarify, here's the final code including border fix:

    public static void Main()
    {
        string sInput = "hi\t bye\t\n";// one\t two\t\n";
        SIZE CharSize;
        Form form = new Form();
        RichTextBox rtfBox = new RichTextBox();
        rtfBox.ContentsResized += (object sender, ContentsResizedEventArgs e) =>
        {
            var richTextBox = (RichTextBox)sender;
            richTextBox.Width = e.NewRectangle.Width;
            richTextBox.Height = e.NewRectangle.Height;
            rtfBox.Width += rtfBox.Margin.Horizontal + SystemInformation.HorizontalResizeBorderThickness;
        };

        rtfBox.WordWrap = false;
        rtfBox.ScrollBars = RichTextBoxScrollBars.None;

        rtfBox.Rtf = @"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil Arial;}}\viewkind4\uc1\trowd\trgaph100\cellx1000\cellx2000\pard\intbl\lang1033\f0\fs20  hi\cell  bye\cell\row\intbl  one\cell  two\cell\row\pard\par}";

        form.Controls.Add(rtfBox);
        form.ShowDialog();
    }
P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348
adrianbanks
  • 81,306
  • 22
  • 176
  • 206
2

It's much easier to use GetPreferredSize, as described in this answer. Then you don't need to wait for a ContentsResized event,

Community
  • 1
  • 1
ulatekh
  • 1,311
  • 1
  • 14
  • 19
0

What about the Height ?
I added

richTextBox.Height += richTextBox.Margin.Vertical +  
SystemInformation.VerticalResizeBorderThickness;  

at the end.

It also looks like a good candidate for an extension method :

static public class RichTextBoxResizer {  
    static public void ResizeToContents(this RichTextBox richTextBox, ContentsResizedEventArgs e) {  
        richTextBox.Width = e.NewRectangle.Width;  
        richTextBox.Height = e.NewRectangle.Height;  

        richTextBox.Width += richTextBox.Margin.Horizontal +  
            SystemInformation.HorizontalResizeBorderThickness +  
            SystemInformation.HorizontalScrollBarThumbWidth;  

        richTextBox.Height += richTextBox.Margin.Vertical +  
            SystemInformation.VerticalResizeBorderThickness;  
    }   

    static public void ResizeToContentsHorizontally(this RichTextBox richTextBox, ContentsResizedEventArgs e) {
        richTextBox.Width = e.NewRectangle.Width;

        richTextBox.Width += richTextBox.Margin.Horizontal +
            SystemInformation.HorizontalResizeBorderThickness +
            SystemInformation.HorizontalScrollBarThumbWidth;
    }

    static public void ResizeToContentsVertically(this RichTextBox richTextBox, ContentsResizedEventArgs e) {
        richTextBox.Height = e.NewRectangle.Height;

        richTextBox.Height += richTextBox.Margin.Vertical +
            SystemInformation.VerticalResizeBorderThickness;
    }
}

So the event sink looks like :

private void rtfBox_ContentsResized(object sender, ContentsResizedEventArgs e) {  
    RichTextBox rtb = (RichTextBox)sender;  
    rtb.ResizeToContents(e);  
}  
Jack Griffin
  • 1,228
  • 10
  • 17