Search code examples
c#.netwinformsrichtextboxautosize

Autoscaling RichTextBox


I am trying to use read-only RichTextBoxes to show user-generated text. The height of the textbox and control should depend on the content and be limited to a certain maximum, anything past that point uses scroll bars.

AutoSize does not appear to work for RTB's

public void Rescale()
{
    Point pt = rtbComment.GetPositionFromCharIndex(rtbComment.Text.Length);
    int height = rtbComment.GetPositionFromCharIndex(rtbComment.Text.Length).Y + (int)rtbComment.SelectionFont.GetHeight();
    if (height > 250)
        height = 250;
    this.Size = new System.Drawing.Size(616, height + 50);
    rtbComment.Size = new System.Drawing.Size(614, height);
}

This works absolutely fine for short comments or comments with little text and many linebreaks, but for long one-liners that are broken into ~4 lines, the point I get from GetPositionFromCharIndex is all wrong - the function puts it somewhere at 105px down on the y-Axis when it's actually closer to 60, making the textbox about twice as big as it's supposed to be.

The width does not appear to be the issue here, as the box starts with the width I am setting it to and reading the point out again produces the same result.


Solution

  • Solved.

    I used the TextRenderer.MeasureText method.

    Since this method ignores the fact that very long lines will receive one or more automated linebreaks in the RichTextBox, I've written a function that manually splits the text into lines of any length by linebreaks, then measures each of these lines to check how many lines it'll use in the RTB.

    Here's the function, in case anyone needs it:

    public int getLines(string comment)
    {
        int height_ln = 0;
    
        string[] lines;
    
        //split into lines based on linebreaks
        if (comment.Contains("\n"))
        {
            lines = comment.Split('\n');
        }
        else
        {
            lines = new string[1];
            lines[0] = comment;
        }
    
        //check each line to see if it'll receive automatic linebreaks
        foreach(string line in lines)
        {
            int text_width = TextRenderer.MeasureText(line, rtbKommentar.Font).Width;
            double text_lines_raw = (double)text_width / 1400; //1400 is the width of my RichTextBox
    
            int text_lines = 0;
    
            if (line.Contains("\r")) //Please don't call me out on this, I'm already feeling dirty
                text_lines = (int)Math.Floor(text_lines_raw);
            else
                text_lines = (int)Math.Ceiling(text_lines_raw);
            if (text_lines == 0)
                text_lines++;
    
            height_ln += text_lines;
        }
        return height_ln; //this is the number of lines required, to adjust the height of the RichTextBox I need to multiply it by 15, which is the font's height.
    }