Find the height of text in a panel - c#

I have panel that I have customized. I use it to display text. But sometimes that text is too long and wraps to the next line. Is there some way I can auto resize the panel to show all the text?
I am using C# and Visual Studio 2008 and the compact framework.
Here is the code I am wanting to adjust the size for:
(Note: HintBox is my own class that inherits from panel. So I can modify it as needed.)
public void DataItemClicked(ShipmentData shipmentData)
{
// Setup the HintBox
if (_dataItemHintBox == null)
_dataItemHintBox = HintBox.GetHintBox(ShipmentForm.AsAnObjectThatCanOwn(),
_dataShipSelectedPoint,
new Size(135, 50), shipmentData.LongDesc,
Color.LightSteelBlue);
_dataItemHintBox.Location = new Point(_dataShipSelectedPoint.X - 100,
_dataShipSelectedPoint.Y - 50);
_dataItemHintBox.MessageText = shipmentData.LongDesc;
// It would be nice to set the size right here
_dataItemHintBox.Size = _dataItemHintBox.MethodToResizeTheHeightToShowTheWholeString()
_dataItemHintBox.Show();
}
I am going to give the answer to Will Marcouiller because his code example was the closest to what I needed (and looks like it will work). However, this is what I think I will use:
public static class CFMeasureString
{
private struct Rect
{
public readonly int Left, Top, Right, Bottom;
public Rect(Rectangle r)
{
this.Left = r.Left;
this.Top = r.Top;
this.Bottom = r.Bottom;
this.Right = r.Right;
}
}
[DllImport("coredll.dll")]
static extern int DrawText(IntPtr hdc, string lpStr, int nCount,
ref Rect lpRect, int wFormat);
private const int DT_CALCRECT = 0x00000400;
private const int DT_WORDBREAK = 0x00000010;
private const int DT_EDITCONTROL = 0x00002000;
static public Size MeasureString(this Graphics gr, string text, Rectangle rect,
bool textboxControl)
{
Rect bounds = new Rect(rect);
IntPtr hdc = gr.GetHdc();
int flags = DT_CALCRECT | DT_WORDBREAK;
if (textboxControl) flags |= DT_EDITCONTROL;
DrawText(hdc, text, text.Length, ref bounds, flags);
gr.ReleaseHdc(hdc);
return new Size(bounds.Right - bounds.Left, bounds.Bottom - bounds.Top +
(textboxControl ? 6 : 0));
}
}
This uses the os level call to draw text. By P-Invoking it I can get the functionality I need (multi line wrapping). Note that this method does not include any margins. Just the actual space taken up by the text.
I did not write this code. I got it from http://www.mobilepractices.com/2007/12/multi-line-graphicsmeasurestring.html. That blog post had my exact problem and this fix. (Though I did make a minor tweak to make it a extension method.)

You could use the Graphics.MeasureString() method.
With a code sample of your text assignment onto your panel, I could perhaps provide a code sample using the MeasureString() method, if you need it.
I have no way to know whether the Graphics.MeasureString() method is part of the Compact Framework, as it is not said on the page I linked.
EDIT #1
Here's a link where I answered to another text-size related question, while I look for writing a sample for you. =)
EDIT #2
Here's another link related to your question. (Next edit is the sample code. =P)
EDIT #3
public void DataItemClicked(ShipmentData shipmentData) {
// Setup the HintBox
if (_dataItemHintBox == null)
_dataItemHintBox = HintBox.GetHintBox(ShipmentForm.AsAnObjectThatCanOwn(),
_dataShipSelectedPoint,
new Size(135, 50), shipmentData.LongDesc,
Color.LightSteelBlue);
// Beginning to measure the size of the string shipmentData.LongDesc here.
// Assuming that the initial font size should be 30pt.
Single fontSize = 30.0F;
Font f = new Font("fontFamily", fontSize, FontStyle.Regular);
// The Panel.CreateGraphics method provides the instance of Graphics object
// that shall be used to compare the string size against.
using (Graphics g = _dataItemHintBox.CreateGraphics()) {
while (g.MeasureString(shipmentData.LongDesc, f).Width > _dataItemHintBox.Size.Width - 5) {
--fontSize;
f = new Font("fontFamily", fontSize, FontStyle.Regular);
}
}
// Font property inherited from Panel control.
_dataItemHintBox.Font = f;
// End of font resizing to fit the HintBox panel.
_dataItemHintBox.Location = new Point(_dataShipSelectedPoint.X - 100,
_dataShipSelectedPoint.Y - 50);
_dataItemHintBox.MessageText = shipmentData.LongDesc;
// It would be nice to set the size right here
_dataItemHintBox.Size = _dataItemHintBox.MethodToResizeTheHeightToShowTheWholeString()
_dataItemHintBox.Show();
}
Disclaimer: This code has not been tested and is off the top of my head. Some changes might be obligatory in order for you to test it. This provides a guideline to achieve what you seem to want to accomplish. There might be a better way to do this, but I know this one works. Well, the algorithm works, as you can see in my other answers.
Instead of the line:
SizeF fontSize = 30.0F;
You could as well do the following:
var fontSize = _dataItemHintBox.Font.Size;
Why is this?
Because Font.Size property is readonly. So, you need to create a new instance of the System.Drawing.Font class each time the Font.Size shall change.
In your comparison, instead of having the line:
while (g.MeasureString(shipmentData.LongDesc, f)...)
you could also have:
while (g.MeasureString(shipmentData.LongDesc, _dataItemHintBox.Font)...)
This would nullify the need for a second Font class instance, that is f.
Please feel free to post feedbacks as I could change my sample to fit your reality upon the feedbacks received, so that it better helps you. =)
I hope this helps! =)

You can use whichever of the TextRenderer.MeasureText overloads is appropriate for you. Using this function, you can determine the actual rendered size of a string and adjust your panel's size accordingly.
If you're trying to measure inside the Paint event, then you could use the MeasureString function on your e.Graphics object, but resizing inside Paint is not wise. Using TextRenderer avoids your having to create a Graphics object with CreateGraphics() and disposing of it when you're finished.
EDIT
Since TextRenderer is not supported on the compact framework (I missed the tag the first time I saw the question), you'll have to use MeasureString() function on the Graphics object. Something like this:
public Size GetStringSize(string text)
{
using(Graphics g = yourPanel.CreateGraphics())
{
return g.MeasureString(text, yourPanel.Font);
}
}

Related

Passing the current platform font into SKTypeface?

When attempting to render Chinese (or other symbolic) text. SkiSharp will render boxes instead of the correct Chinese characters. Obviously the font that Skia is using by default doesn't support those characters. So we have to assign our own SKTypeface using a font that does support those characters.
My initial strategy was to simply include the necessary fonts to render those characters, which worked fine. However when supporting multiple different symbolic languages with their own fonts, the application size grows dramatically (about 15 mb per font).
So thinking about this a bit more... The default platform fonts seems to support any of these symbolic characters just fine. What I mean by this, is that the font that is used by default renders Buttons, labels and titles perfectly.
So my current thought is, why can't I just pass, whatever font that is into a SKTypeface for my control?
The problem is that I don't know how to get ahold of whatever that fall-back or default font is in order to create a new SKTypeface with it.
My Question
How can I create an SKTypeface from the same font that is rendering these buttons, labels and titles just fine?
note: if you need anything from me to help you understand the problem
or solve the problem just let me know.
You should be able to use SKFontManager.MatchCharacter or one of its overloads in order to:
Use the system fallback to find a typeface for the given character.
Below is an example based on SkiaSharp WindowsSample's TextSample:
public class TextSample : SampleBase
{
// ...
protected override void OnDrawSample(SKCanvas canvas, int width, int height)
{
canvas.DrawColor(SKColors.White);
const string text = "象形字";
var x = width / 2f;
// in my case the line below returns typeface with FamilyName `Yu Gothic UI`
var typeface = SKFontManager.Default.MatchCharacter(text[0]);
using (var paint = new SKPaint())
{
paint.TextSize = 64.0f;
paint.IsAntialias = true;
paint.Color = (SKColor)0xFF4281A4;
paint.IsStroke = false;
paint.Typeface = typeface; // use typeface for the first one
paint.TextAlign = SKTextAlign.Center;
canvas.DrawText(text, x, 64.0f, paint);
}
using (var paint = new SKPaint())
{
// no typeface here
paint.TextSize = 64.0f;
paint.IsAntialias = true;
paint.Color = (SKColor)0xFF9CAFB7;
paint.IsStroke = true;
paint.StrokeWidth = 3;
paint.TextAlign = SKTextAlign.Center;
canvas.DrawText(text, x, 144.0f, paint);
}
}
}
And below is the output

Creating a transparent portion of a control to see controls underneath it

I've modified the SuperContextMenuStrip found at CodeProject to meet some of my projects needs. I'm using it as a tooltip for map markers on a GMap.NET Map Control. Here is a sample of what it looks like:
What I would like to do is pretty this up a little by making it look more like a bubble. Similar to an old Google Maps stytle tooltip:
I've spent some time searching on control transparency and I know this isn't an easy thing. This SO question in particular illustrates that.
I have considered overriding the OnPaint method of the SuperContextMenuStrip to draw a background of the GMap.NET control that is underneath the SuperContextMenuStrip, but even that would fail in cases where the marker is hanging off the GMap.NET control:
What is the correct way to create the type of transparency I am looking for?
In Windows Forms, you achieve transparency (or draw irregularly shaped windows) by defining a region. To quote MSDN
The window region is a collection of pixels within the window where
the operating system permits drawing.
In your case, you should have a bitmap that you will use as a mask. The bitmap should have at least two distinct colors. One of these colors should represent the part of the control that you want to be transparent.
You would then create a region like this:
// this code assumes that the pixel 0, 0 (the pixel at the top, left corner)
// of the bitmap passed contains the color you wish to make transparent.
private static Region CreateRegion(Bitmap maskImage) {
Color mask = maskImage.GetPixel(0, 0);
GraphicsPath grapicsPath = new GraphicsPath();
for (int x = 0; x < maskImage.Width; x++) {
for (int y = 0; y < maskImage.Height; y++) {
if (!maskImage.GetPixel(x, y).Equals(mask)) {
grapicsPath.AddRectangle(new Rectangle(x, y, 1, 1));
}
}
}
return new Region(grapicsPath);
}
You would then set the control’s Region to the Region returned by the CreateRegion method.
this.Region = CreateRegion(YourMaskBitmap);
to remove the transparency:
this.Region = new Region();
As you can probably tell from the code above, creating regions is expensive resource-wise. I'd advice saving regions in variables should you need to use them multiple times. If you use cached regions this way, you'd soon experience another problem. The assignment would work the first time but you would get an ObjectDisposedException on subsequent calls.
A little investigation with refrector would reveal the following code within the set accessor of the Region Property:
this.Properties.SetObject(PropRegion, value);
if (region != null)
{
region.Dispose();
}
The Region object is disposed after use!
Luckily, the Region is clonable and all you need to do to preserve your Region object is to assign a clone:
private Region _myRegion = null;
private void SomeMethod() {
_myRegion = CreateRegion(YourMaskBitmap);
}
private void SomeOtherMethod() {
this.Region = _myRegion.Clone();
}

Determining exact glyph height in specified font

I have searched a lot and tried much but I can not find the proper solution.
I wonder is there any approach for determining exact glyph height in specified font?
I mean here when I want to determine the height of DOT glyph I should receive small height but not height with paddings or the font size.
I have found the solution for determining exact glyph width here (I have used the second approach) but it does not work for height.
UPDATE: I need solution for .NET 1.1
It's not that hard to get the character metrics. GDI contains a function GetGlyphOutline that you can call with the GGO_METRICS constant to get the height and width of the smallest enclosing rectangle required to contain the glyph when rendered. I.e, a 10 point glyph for a dot in font Arial will give a rectangle of 1x1 pixels, and for the letter I 95x.14 if the font is 100 points in size.
These are the declaration for the P/Invoke calls:
// the declarations
public struct FIXED
{
public short fract;
public short value;
}
public struct MAT2
{
[MarshalAs(UnmanagedType.Struct)] public FIXED eM11;
[MarshalAs(UnmanagedType.Struct)] public FIXED eM12;
[MarshalAs(UnmanagedType.Struct)] public FIXED eM21;
[MarshalAs(UnmanagedType.Struct)] public FIXED eM22;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINTFX
{
[MarshalAs(UnmanagedType.Struct)] public FIXED x;
[MarshalAs(UnmanagedType.Struct)] public FIXED y;
}
[StructLayout(LayoutKind.Sequential)]
public struct GLYPHMETRICS
{
public int gmBlackBoxX;
public int gmBlackBoxY;
[MarshalAs(UnmanagedType.Struct)] public POINT gmptGlyphOrigin;
[MarshalAs(UnmanagedType.Struct)] public POINTFX gmptfxGlyphOrigin;
public short gmCellIncX;
public short gmCellIncY;
}
private const int GGO_METRICS = 0;
private const uint GDI_ERROR = 0xFFFFFFFF;
[DllImport("gdi32.dll")]
static extern uint GetGlyphOutline(IntPtr hdc, uint uChar, uint uFormat,
out GLYPHMETRICS lpgm, uint cbBuffer, IntPtr lpvBuffer, ref MAT2 lpmat2);
[DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
The actual code, rather trivial, if you don't consider the P/Invoke redundancies. I tested the code, it works (you can adjust for getting the width as well from GLYPHMETRICS).
Note: this is ad-hoc code, in the real world, you should clean up the HDC's and objects with ReleaseHandle and DeleteObject. Thanks to a comment by user2173353 to point this out.
// if you want exact metrics, use a high font size and divide the result
// otherwise, the resulting rectangle is rounded to nearest int
private int GetGlyphHeight(char letter, string fontName, float fontPointSize)
{
// init the font. Probably better to do this outside this function for performance
Font font = new Font(new FontFamily(fontName), fontPointSize);
GLYPHMETRICS metrics;
// identity matrix, required
MAT2 matrix = new MAT2
{
eM11 = {value = 1},
eM12 = {value = 0},
eM21 = {value = 0},
eM22 = {value = 1}
};
// HDC needed, we use a bitmap
using(Bitmap b = new Bitmap(1,1))
using (Graphics g = Graphics.FromImage(b))
{
IntPtr hdc = g.GetHdc();
IntPtr prev = SelectObject(hdc, font.ToHfont());
uint retVal = GetGlyphOutline(
/* handle to DC */ hdc,
/* the char/glyph */ letter,
/* format param */ GGO_METRICS,
/* glyph-metrics */ out metrics,
/* buffer, ignore */ 0,
/* buffer, ignore */ IntPtr.Zero,
/* trans-matrix */ ref matrix);
if(retVal == GDI_ERROR)
{
// something went wrong. Raise your own error here,
// or just silently ignore
return 0;
}
// return the height of the smallest rectangle containing the glyph
return metrics.gmBlackBoxY;
}
}
Can you update the question to include what you have tried ?
By dot glyph I assume you mean the punctuation mark detailed here ?
Is this Glyph height displayed on screen or a printed page ?
I managed to modify the first method in the link you posted in order to count the matching vertical pixels, however identifying the largest height of the glyph is fiddly to do unless you are willing to draw character by character, so this wasn't really a general working solution like the article.
In order to have a general working solution would need identify the largest single pixel vertical region of the character / glyph, then count the number of pixels in that region.
I also managed to verify that Graphics.MeasureString, TextRenderer.MeasureText and Graphics.MeasureCharacterRanges all returned the bounding box which gave a number similar to the font height.
The alternative to this is to Glyph.ActualHeight property which gets the rendered height of the framework element. This part of WPF and the related GlyphTypeface and GlyphRun classes. I wasn't able to test them at this time having only Mono.
The steps for getting Glyph.ActualHeight are as follows
Initialise the arguments for GlyphRun
Initialise GlyphRun object
Access relevant Glyph using glyphTypeface.CharacterToGlyphMap[text[n]] or more correctly glyphTypeface.GlyphIndices[n], where glyphTypeface is your GlyphTypeface, which is created from the Typeface object you make in Step 1.
Relevant resources on using them include
The Thing about Glyphs
GlyphRun and So Forth
Measuring Text
Glyphs Particularly the picture the bottom.
Futher references on GDI (What these classes use under the hood is GDI or GDI+) and Fonts in Windows include
GDI
Windows Font Mapping
Here's a solution involving WPF. We create an intermediate Geometry object in order to retrieve the accurate bounding box of our text. The advantage of this solution is that it does not actually render anything. Even if you don't use WPF for your interface, you may use this piece of code to do your measurements only, assuming the font rendering size would be the same in GDI, or close enough.
var fontFamily = new FontFamily("Arial");
var typeface = new Typeface(fontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
var fontSize = 15;
var formattedText = new FormattedText(
"Hello World",
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
typeface,
fontSize,
Brushes.Black);
var textGeometry = formattedText.BuildGeometry(new Point(0, 0));
double x = textGeometry.Bounds.Left;
double y = textGeometry.Bounds.Right;
double width = textGeometry.Bounds.Width;
double height = textGeometry.Bounds.Height;
Here, "Hello world" measurements are about 77 x 11 units. A single dot gives 1.5 x 1.5.
As an alternative solution, still in WPF, you could use GlyphRun and ComputeInkBoundingBox(). It's a bit more complex and won't support automatic font substitution, though. It would look like this:
var glyphRun = new GlyphRun(glyphTypeFace, 0, false, fontSize,
glyphIndexList,
new Point(0, 0),
advanceWidths,
null, null, null, null,
null, null);
Rect glyphInkBox = glyphRun.ComputeInkBoundingBox();

Measure String inside RichTextBox Control

Can somebody please explain how I would go about measuring the string inside a richtextbox control so that the I can automatically resize the richtextbox control according to its content?
Thank you
Edit:
I've thought about it, and since the below answer won't work if there are different fonts in the RichTextBox Control, what if, I could get the upper-left coords of the richtextbox control and then get the bottom-right coords of the very last line of text inside the rtb. That would essentially give me the Width and Height of the string inside the RichTextBox Control. Is this possible? Or is this a bad idea to do it this way?
Put the following code in the ContentsResized event:
Private Sub rtb_ContentsResized(ByVal sender As Object, ByVal e As System.Windows.Forms.ContentsResizedEventArgs) Handles txtQuestion.ContentsResized
Dim h = e.NewRectangle.Height, w = e.NewRectangle.Width
h = Math.Max(h, sender.Font.Height)
h = Math.Min(h, Me.ClientSize.Height - 10 - sender.Top)
h += sender.Height - sender.ClientSize.Height + 1
sender.Height = h
End Sub
Assuming that someone is typing into the control, you could use an event to fire every time a character is entered (increment counter) and decrement when it is deleted. This would give you a true count.
Edit:
Have you tried this to adjust the height?
richTextBox1.Height = (int)(1.5 * richTextBox1.Font.Height) + richTextBox1.GetLineFromCharIndex(richTextBox1.Text.Length + 1) * richTextBox1.Font.Height + 1 + richTextBox1.Margin.Vertical;
richTextBox1.SelectionStart = 0;
richTextBox1.SelectionStart = richTextBox1.Text.Length;
Or you can do this using Width:
Graphics g = Graphics.FromHwnd(richTextBox1.Handle);
SizeF f = g.MeasureString(richTextBox1.Text, richTextBox1.Font);
richTextBox1.Width = (int)(f.Width)+5;
Try calling GetPreferredSize(Size.Empty). It is defined in the Control class, and if overriden property by the RichTextBoxControl, ought to give you what you are looking for.
If you pass something other than Size.Empty into the method, then it will use that value as a maximum constraint. Using Size.Empty means that the potential size is unbounded.
You can measure a string by calling TextRenderer.MeasureText.
However, if the text contains multiple fonts, this will not work.
EDIT: You're looking for the GetPositionFromCharIndex method.
Note that if there are multiple lines, you should take the max of the X coordinates of the last character on each line.
I found a solution for the Rich text box height issues.. i have modified it a for general use..
Create following structs in your application....
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}
[StructLayout(LayoutKind.Sequential)]
public struct SCROLLBARINFO {
public Int32 cbSize;
public RECT rcScrollBar;
public Int32 dxyLineButton;
public Int32 xyThumbTop;
public Int32 xyThumbBottom;
public Int32 reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public Int32[] rgstate;
}
Create following private variables in your class for form (where ever you need to calculate rich text height)
private UInt32 SB_VERT = 1;
private UInt32 OBJID_VSCROLL = 0xFFFFFFFB;
[DllImport("user32.dll")]
private static extern
Int32 GetScrollRange(IntPtr hWnd, UInt32 nBar, out Int32 lpMinPos, out Int32 lpMaxPos);
[DllImport("user32.dll")]
private static extern
Int32 GetScrollBarInfo(IntPtr hWnd, UInt32 idObject, ref SCROLLBARINFO psbi);
Add following method to your Class for form
private int CalculateRichTextHeight(string richText) {
int height = 0;
RichTextBox richTextBox = new RichTextBox();
richTextBox.Rtf = richText;
richTextBox.Height = this.Bounds.Height;
richTextBox.Width = this.Bounds.Width;
richTextBox.WordWrap = false;
int nHeight = 0;
int nMin = 0, nMax = 0;
SCROLLBARINFO psbi = new SCROLLBARINFO();
psbi.cbSize = Marshal.SizeOf(psbi);
richTextBox.Height = 10;
richTextBox.ScrollBars = RichTextBoxScrollBars.Vertical;
int nResult = GetScrollBarInfo(richTextBox.Handle, OBJID_VSCROLL, ref psbi);
if (psbi.rgstate[0] == 0) {
GetScrollRange(richTextBox.Handle, SB_VERT, out nMin, out nMax);
height = (nMax - nMin);
}
return height;
}
You may need to modify above method to make it work as per your requirement...
Make sure to send Rtf string as parameter to method not normal text and also make sure to assign available width and height to the Richtextbox variable in the method...
You can play with WordWrap depending on your requirement...
Add on to bathineni's great answer:
Background: I needed to measure RTF output height for rendering onto paper and because I have custom dynamic page headers/footers I needed to control paging).
(RichTextBox.GetLineFromCharIndex let me down because of complex RTF; including lines & multi column Tables with wordwrap).
Anyhow all was working fine, until someone else used my app with the dreaded windows "Make text and other items larger or smaller" (DPI settings.) - in short now measuring bigger sized fonts it screwed up the page length calculations. (the printer still rendered the text and columns correctly - only the page lengths were now all wrong.)
Only factoring DPI difference failed as in short bigger text didn't fit properly into source RTF tx and cellx values.
Anyhow, in case others are doing similar crazy things bit of trial and error came up with the following (eventually very few) mods to the bathineni CalculateRichTextHeight method:
RichTextBox richTextBox = new RichTextBox(); // same as original
int dpix = richTextBox.CreateGraphics().DpiX; // get dpi
richTextBox.WordWrap = true; // I needed this, you many not
// ... set size etc - same as original answer
richTextBox.Scale(new System.Drawing.SizeF(dpix / 96, dpix / 96)); // scale RTB
// ...
// 96? my original calculations based on windows default 96dpi settings.
Seems the otherwise obscure Control.Scale(sizef) is actually useful for something after all.
Note: if converting results to actual printed lines, (in my case all my \pard's were "\sl-240\slmult0" which comes out to 16 (pix?) per line) also remember to re-factor the divisor.
i.e. in my case:
lines = height / (int)(16 * (dpix / 96))

AutoSize for Label / TextBox in .NET Compact Framework

I'm quite simply going totally bonkers with the omission of the AutoSize-property for the Label and TextBox controls in .NET Compact Framework. I have a simple app, that's supposed to list a bunch of text data (generally between one-liners to a few paragraphs of text) in a TabControl. Everything else works smoothly, but my attempts at dynamically resizing the Label / TextBox -controls I use to display the text are failing miserably.
Here's the way I've tried doing it:
/*
Variables:
s = The text intended for the TextBox
NewTB = TextBox object
width = Intended width
whiteSpaceAdjustment = amount of pixels per line to adjust "wasted" whitespace due to wrapping
*/
String[] linesArray = s.Replace(Environment.NewLine, "\n").Split(new char[] { '\n' });
int lines = 0;
int lineHeight = g.MeasureString(
s.Replace("\n", "").Replace("\r", ""),
LabelFont
).ToSize().Height;
foreach (String str in linesArray) {
if (str.Length == 0) {
lines++;
continue;
}
szz = g.MeasureString(str, LabelFont).ToSize();
lines += szz.Width / (width - whiteSpaceAdjustment);
lines += (szz.Width % width) != 0 ? 1 : 0;
}
NewTB.Height = lines * lineHeight;
NewTB.Width = width;
...but the problem is that the range needed for whiteSpaceAdjustment is too huge. When it's large enough to actually work on the most extreme cases (paragraphs made mostly up of really long words), most boxes end up being a line or two too tall.
I'm probably going to have to implement word wrapping myself, but before I go there, is there anybody with a nice clean solution ready for this?
I'd be forever grateful!
Try this article
www.mobilepractices.com/2007/12/multi-line-graphicsmeasurestring.html
Make sure you also look at the link at the bottom of the article to be able to use different fonts.
If you are using .Net CF 3.5 you may be able to turn their example into an extension method. Otherwise I'd suggest that you create a new control inheriting from the framework control.
This is what I developed for auto re-size width of label in WinCE.
/// <summary>
/// This class provides dynamic size labels, i.e. as the text grows lable width will grow with it.
/// </summary>
public partial class AutoSizeLabel : UserControl
{
private string _strText;
private const int padding = 10;
public AutoSizeLabel()
{
InitializeComponent();
}
public override string Text
{
get
{
return _strText;
}
set
{
_strText = value;
Refresh();
}
}
protected override void OnPaint(PaintEventArgs pe)
{
SizeF size = pe.Graphics.MeasureString(this.Text, this.Font);
this.Size = new Size((int)size.Width + padding, this.Height);
if (this.Text.Length > 0)
{
pe.Graphics.DrawString(this.Text,
this.Font,
new SolidBrush(this.ForeColor),
(this.ClientSize.Width - size.Width) / 2,
(this.ClientSize.Height - size.Height) / 2);
}
// Calling the base class OnPaint
base.OnPaint(pe);
}
}

Categories

Resources