I want to measure the height of the text given a certain width of available canvas. The text that I pass in is really long and I know will wrap. To that end, I call the following:
using System.Windows.Forms;
...
string text = "Really really long text that is sure to wrap...";
Font font = new Font("Arial", 14);
Size canvas = new Size(1100, 850);
Size size = TextRenderer.MeasureText(text, font, canvas);
No matter what I pass in for canvas, it always returns 14 for size.Height
.
Am I missing something simple?
Please, use the TextFormatFlags measure parameter as shown below:
Size size = TextRenderer.MeasureText(text, font, canvas, TextFormatFlags.WordBreak);
DimitryG's solution seems to work great, but only when there is no word big enough to fill more than an entire row. If such word exists, the width will be bigger than the proposed width. There is the flag TextFormatFlags.EndEllipsis
for this case, however I didn't manage to combine the flags in a way so the output is correct (if I use TextFormatFlags.WordEllipsis | TextFormatFlags.WordBreak
the width is correct, but the height is not updated when Word Ellipsis takes place, which means that the big word will be trimmed, but the height will be the same as if it's not trimmed). I also tried the flag TextFormatFlags.EndEllipsis
but with no results.
So until someone makes this clear, I propose using a TextBox
for word wrap, and then multiply the number of lines in the TextBox
with the Font
's height.
Code:
int MeasureMultilineTextHeigh(string text, Font font, int proposedWidth)
{
// Exception handling.
TextBox textBox = new TextBox()
{
Multiline = true,
BorderStyle = BorderStyle.None,
Width = proposedWidth,
Font = font,
Text = text,
};
int lineCount = textBox.GetLineFromCharIndex(int.MaxValue) + 1;
int fontHeight = TextRenderer.MeasureText("X", font).Height;
return lineCount * fontHeight;
}
However this approach has one problem: If, and only if Multiline
property of a TextBox
is set to true
, every Font
will have its own left and right padding. See this stackoverflow.com question and this social.msdn.microsoft.com question for more details. So this means that in some situations the returned value might be bigger than expected. To solve this problem you can use the SetPadding
function to remove the padding (you can find the method as an answer in the first question), code:
private const int EM_SETRECT = 0xB3;
[DllImport(@"User32.dll", EntryPoint = @"SendMessage", CharSet = CharSet.Auto)]
private static extern int SendMessageRefRect(IntPtr hWnd, uint msg, int wParam, ref RECT rect);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public readonly int Left;
public readonly int Top;
public readonly int Right;
public readonly int Bottom;
private RECT(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public RECT(Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom) { }
}
public void SetPadding(TextBox textBox, Padding padding)
{
var rect = new Rectangle(padding.Left, padding.Top, textBox.ClientSize.Width - padding.Left - padding.Right, textBox.ClientSize.Height - padding.Top - padding.Bottom);
RECT rc = new RECT(rect);
SendMessageRefRect(textBox.Handle, EM_SETRECT, 0, ref rc);
}
int MeasureMultilineTextHeigh(string text, Font font, int proposedWidth)
{
// Exception handling.
TextBox textBox = new TextBox()
{
Multiline = true,
BorderStyle = BorderStyle.None,
Width = proposedWidth,
Font = font,
};
SetPadding(textBox, Padding.Empty);
textBox.Text = text;
int lineCount = textBox.GetLineFromCharIndex(int.MaxValue) + 1;
int fontHeight = TextRenderer.MeasureText("X", font).Height;
return lineCount * fontHeight;
}
Needed using statements:
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
I hope this helps. Sorry for my English, if I made any mistake.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With