resize a richtextbox

How do I resize a RichTextBox control to be as high as its content? There appears to beno way to do this.

I've seen several "solutions" which all basically revolve around this code:


RichTextBox1.Height = RichTextBox1.Font.GetHeight * RichTextBox1.Lines.Length


that is; count the number of lines and times it by the height of the font.

Unfortunately, this counts the height of the first font on the rich text control that it encounters, which doesNOT solve the problem. Rich Text can contain multiple fonts, multiple font-heights and even embedded graphics (which aren't even counted by the .Lines property!), so the calculation is doomed before it begins. I thought there might be a property which tells you the scrolling height of the control's contents, but can't see such a property. I also thought I could somehow expand the control to an enormous height and then shrink it until a scrollbar would appear, but I don't know how to do that.

I'm completely stuck. Has somebody found a neat solution?

[1332 byte] By [frumbert] at [2007-12-17]
# 1

Hi,

Try this, using the Find method of the RichTextBox to select each line, and manually computes the Font.Height of each of the line:

int start = 0;
int height = 0;

foreach(string text in richTextBox1.Lines)
{
int textloc = richTextBox1.Find(text, start,
RichTextBoxFinds.WholeWord | RichTextBoxFinds.MatchCase);

height += richTextBox1.SelectionFont.Height;
start += text.Length;
}

richTextBox1.Height = height;

Regards,

-chris

gwapo at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms General...
# 2
This is definately closer. Good idea, but unfortunately it doesn't work. :(

A RichText can (and in my case, does) contain markup which is richer than plain lines - tables, images, borders and whatnot. As I mentioned, these do not seem counted in the Lines collection, yet they obviously do contribute to the height of the control. Some different types of rich text cause the code to crash - for instance, tables cut and paste into a richtextbox from Word will usually crash it, whereas tables cut and paste from other RTF sources don't. Wierd!

Another issue here seems to be (although I could be wrong) is that the lines seem to mean "paragraphs". A line may wrap because the control isn't wide enough, but it still only counts lines as "line breaks". This may explain why graphics and tables cause it trouble. My document may only have 5 line breaks but in fact have 10 lines, so this method of calculating the height doesn't work.

frumbert at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms General...
# 3
Hi,

In addition, RichTextBox has a support for Zooming (ZoomFactor property) in which will increase the size of its content base on zoom factor. Thanks for the explanation, I think in your situation, it's best to dig into the RTF format and calculate height from there. I seen other approach (Sorry I lost the code) previously posted in codeproject that they calculate the height of RichTextBox from its vertical scrollbar by hooking into it (I think it is something like increasing the height until there is no longer a vertical scrollbar).

I'm interrested on solution for this as well, since my upcoming project involves RichTextBox too. I think I'm gonna watch this thread for solution of how to work with your problems as well, since I may encounter the same.
-chris

gwapo at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms General...
# 4
For posterity, CreateGraphics and MeasureString don't work. The example from the help is:



Private Sub AutoSizeControl(control As Control, textPadding As Integer)
' Create a Graphics object for the Control.
Dim g As Graphics = control.CreateGraphics()

' Get the Size needed to accommodate the formatted Text.
Dim preferredSize As Size = g.MeasureString( _
control.Text, control.Font).ToSize()

' Pad the text and resize the control.
control.ClientSize = New Size( _
preferredSize.Width + textPadding * 2, _
preferredSize.Height + textPadding * 2)

' Clean up the Graphics object.
g.Dispose()
End Sub

This code measures the length of a string and resizes the control to be that size. This works a treat for controls like buttons a textboxes, but anything with a scrollbar isn't resized properly (try a multi-line text box) because it fails to take into account the space the scrollbars themselves take up. When used with a RichTextBox it often (in my tests) makes it's size (0,0) even if it has content.

Will trawl codeproject again looking for solutions that use the scrolling height to work it out.

Thanks for your ideas, Chris.

frumbert at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms General...
# 5
No prob :)

Keep this thread posted for any solution you may get.
Thanks as well.

-chris

gwapo at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms General...
# 6
I belive I'm much closer to a solution with this - 99% in fact. I'm having some troubles with the code below in gaining the width of the scrollbar, which is a side issue where I sometimes need to know how wide it is (returns 0).

The form class has RichTextBox1 which contain some rtf (loaded from an embedded resource). It also has a button which resizes the RichTextBox based on the size of its contents. It then turns off the scrollbars, because the scrollbars appear over the inner edge of the object and therefore take up some of its space.

Though I made this code mostly myself, I found these references helpful in creating this code:

http://www.dotnet247.com/247reference/msgs/40/203979.aspx

http://www.vbnet.ru/faq/showtopic.asp?id=316

http://www.codeproject.com/vb/net/VbNetScrolling.asp

I've split the scrollbar stuff off into a seperate class to make it a bit more reusable. If you can see any mistakes or can solve the scrollbar width/height issue please let me know.


' For showing an embedded resource
Imports System.Reflection
' for StructLayout
Imports System.Runtime.InteropServices
' for SizeOf
Imports System.Runtime.InteropServices.Marshal

Public Class resize
Inherits System.Windows.Forms.Form

' Windows Form Designer generated code REMOVED

Private Sub resize_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim Assm As [Assembly] = Me.GetType().Assembly
Dim RtfStream As System.IO.Stream = Assm.GetManifestResourceStream("MyProject1.Heading2.rtf")
If Not RtfStream Is Nothing Then
Me.RichTextBox1.LoadFile(RtfStream, RichTextBoxStreamType.RichText)
RtfStream.Close()
End If
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
FitContents(RichTextBox1)
RichTextBox1.ScrollBars = RichTextBoxScrollBars.None
End Sub

Private Sub FitContents(ByVal ctrl As Control)
If Not ctrl Is Nothing Then
Dim si As New ScrollingInfo
Dim h As Integer = si.getScroll(ctrl.Handle, ScrollingInfo.enScrollType.SBS_VERT).nMax
Dim w As Integer = si.getScroll(ctrl.Handle, ScrollingInfo.enScrollType.SBS_HORZ).nMax
If w < ctrl.Width Then w = ctrl.Width
If h < ctrl.Height Then h = ctrl.Height
ctrl.Size = New Size(w + si.ScrollbarWidth, h + si.ScrollbarHeight)
End If
End Sub

End Class

Public Class ScrollingInfo
Const SIF_RANGE = 1
Const SIF_PAGE = 2
Const SIF_POS = 4
Const SIF_DISABLENOSCROLL = 8
Const SIF_TRACKPOS = 10
Const SIF_ALL = (SIF_RANGE Or SIF_PAGE Or SIF_POS Or SIF_TRACKPOS)

Private Declare Function GetSystemMetrics Lib "user32.dll" (ByVal Metric As Integer) As Integer

Private Declare Function GetScrollInfo Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal nBar As Integer, ByRef lpScrollInfo As SCROLLINFO) As Boolean

<StructLayout(LayoutKind.Sequential)> _
Public Structure SCROLLINFO
Public cbSize As Integer
Public fMask As Integer
Public nMin As Integer
Public nMax As Integer
Public nPage As Integer
Public nPos As Integer
Public nTrackPos As Integer
End Structure

Enum enScrollType
SBS_HORZ = 0
SBS_VERT = 1
End Enum

Enum enSysMetric ' /sysinfo/base/getsystemmetrics.htm
SM_CYHSCROLL = 3
SM_CXVSCROLL = 20
End Enum

ReadOnly Property ScrollbarWidth() As Integer
Get
GetSystemMetrics(enSysMetric.SM_CXVSCROLL)
End Get
End Property
ReadOnly Property ScrollbarHeight() As Integer
Get
Return GetSystemMetrics(enSysMetric.SM_CYHSCROLL)
End Get
End Property

Public Function getScroll(ByVal hWnd As IntPtr, Optional ByVal ScrollType As enScrollType = enScrollType.SBS_VERT) As SCROLLINFO
Dim sc As New SCROLLINFO
sc.fMask = SIF_ALL
sc.cbSize = SizeOf(sc)
If GetScrollInfo(hWnd, ScrollType, sc) Then
Return sc
End If
End Function

End Class


frumbert at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms General...
# 7
Hi, I found one of your posts here in google cache, but cannot get to the post here anymore...

It is about richtextbox with toolbar...

How can I see your example about that ?

Thank you

Duray AKAR

durayakar at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms General...
# 8

I'd pretty much forgotten about it, but fortunately put an archive of it on my blog:

http://frumbert.org/2005/01/vbnet_richtextbox_editor.html

Also put the code to get the height of the content of a RichText control on my site too:

http://frumbert.org/2005/08/vbnet_richtextbox_control_resi.html

(Both have .zip downloads of the solution code)

frumbert at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms General...
# 9
Thank you,

You just saved me a lot of time :)

durayakar at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms General...
# 10

Why so much trouble? Can't you simply use the ContentsResized event of the RichTextBox?

SRavi at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms General...
# 11

Ravi,

Can you say the code for Resizing the RichTextBox at run time when paste any text inside the RichTextBox it goes beyound the total height of the RichTextBox.

with Regards,

Vimal

Vimal@.Net at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms General...