How to truncate a string so that it fits in a container?

There are many questions (EG: 1 , 2 , 3 , 4 , 5 ) asking how you can truncate a string to the required number of characters. But I want the text fragment to be truncated to fit into the container. (IE: crop the string in pixels , not characters ).

This is easy if you use WPF, but not so much in WinForms ...

So: how can you truncate a string to fit in a container?

+7
c # winforms truncate
source share
2 answers

After a day of coding, I found a solution, and I wanted to share it with the community.

First of all: there is no built-in truncation function for a string or winforms TextBox. If you use a shortcut, you can use the AutoEllipsis property.

FYI: An ellipsis is a punctuation mark made up of three dots. IE: ...

This is why I did it:

public static class Extensions { /// <summary> /// Truncates the TextBox.Text property so it will fit in the TextBox. /// </summary> static public void Truncate(this TextBox textBox) { //Determine direction of truncation bool direction = false; if (textBox.TextAlign == HorizontalAlignment.Right) direction = true; //Get text string truncatedText = textBox.Text; //Truncate text truncatedText = truncatedText.Truncate(textBox.Font, textBox.Width, direction); //If text truncated if (truncatedText != textBox.Text) { //Set textBox text textBox.Text = truncatedText; //After setting the text, the cursor position changes. Here we set the location of the cursor manually. //First we determine the position, the default value applies to direction = left. //This position is when the cursor needs to be behind the last char. (Example:"…My Text|"); int position = 0; //If the truncation direction is to the right the position should be before the ellipsis if (!direction) { //This position is when the cursor needs to be before the last char (which would be the ellipsis). (Example:"My Text|…"); position = 1; } //Set the cursor position textBox.Select(textBox.Text.Length - position, 0); } } /// <summary> /// Truncates the string to be smaller than the desired width. /// </summary> /// <param name="font">The font used to determine the size of the string.</param> /// <param name="width">The maximum size the string should be after truncating.</param> /// <param name="direction">The direction of the truncation. True for left (…ext), False for right(Tex…).</param> static public string Truncate(this string text, Font font, int width, bool direction) { string truncatedText, returnText; int charIndex = 0; bool truncated = false; //When the user is typing and the truncation happens in a TextChanged event, already typed text could get lost. //Example: Imagine that the string "Hello Worl" would truncate if we add 'd'. Depending on the font the output //could be: "Hello Wor…" (notice the 'l' is missing). This is an undesired effect. //To prevent this from happening the ellipsis is included in the initial sizecheck. //At this point, the direction is not important so we place ellipsis behind the text. truncatedText = text + "…"; //Get the size of the string in pixels. SizeF size = MeasureString(truncatedText, font); //Do while the string is bigger than the desired width. while (size.Width > width) { //Go to next char charIndex++; //If the character index is larger than or equal to the length of the text, the truncation is unachievable. if (charIndex >= text.Length) { //Truncation is unachievable! //Throw exception so the user knows what going on. throw new IndexOutOfRangeException("The desired width of the string is too small to truncate to."); } else { //Truncation is still applicable! //Raise the flag, indicating that text is truncated. truncated = true; //Check which way to text should be truncated to, then remove one char and add an ellipsis. if (direction) { //Truncate to the left. Add ellipsis and remove from the left. truncatedText = "…" + text.Substring(charIndex); } else { //Truncate to the right. Remove from the right and add the ellipsis. truncatedText = text.Substring(0, text.Length - charIndex) + "…"; } //Measure the string again. size = MeasureString(truncatedText, font); } } //If the text got truncated, change the return value to the truncated text. if (truncated) returnText = truncatedText; else returnText = text; //Return the desired text. return returnText; } /// <summary> /// Measures the size of this string object. /// </summary> /// <param name="text">The string that will be measured.</param> /// <param name="font">The font that will be used to measure to size of the string.</param> /// <returns>A SizeF object containing the height and size of the string.</returns> static private SizeF MeasureString(String text, Font font) { //To measure the string we use the Graphics.MeasureString function, which is a method that can be called from a PaintEventArgs instance. //To call the constructor of the PaintEventArgs class, we must pass a Graphics object. We'll use a PictureBox object to achieve this. PictureBox pb = new PictureBox(); //Create the PaintEventArgs with the correct parameters. PaintEventArgs pea = new PaintEventArgs(pb.CreateGraphics(), new System.Drawing.Rectangle()); pea.Graphics.PageUnit = GraphicsUnit.Pixel; pea.Graphics.PageScale = 1; //Call the MeasureString method. This methods calculates what the height and width of a string would be, given the specified font. SizeF size = pea.Graphics.MeasureString(text, font); //Return the SizeF object. return size; } } 

Usage: This is a class that you can copy and paste into the namespace containing the winforms form. Make sure you enable " using System.Drawing; "

This class has two extension methods called Truncate. You can basically do this:

 public void textBox1_TextChanged(object sender, EventArgs e) { textBox1.Truncate(); } 

Now you can enter something in textBox1, and if necessary, it will automatically truncate your line to fit in textBox, and it will add an ellipsis.

Overview: This class currently contains 3 methods:

  • Truncation (extension for TextBox)
  • Truncation (extension for string)
  • MeasureString

Truncation (extension for TextBox)

This method automatically trims the TextBox.Text property. The direction of truncation is limited by the TextAlign property. (EG: "Truncate for left alignment ...", "... ncation for proper alignment".) Please note: this method may require some modification to work with other writing systems, such as Hebrew or Arabic.


Truncation (extension for string)

To use this method, you must pass two parameters: the font and the desired width. The font is used to calculate the width of the line, and the required width is used as the maximum width allowed after truncation.


MeasureString

This method is closed in a piece of code. Therefore, if you want to use it, you must first transfer it to the publication. This method is used to measure the height and width of a line in pixels. Two parameters are required for this: the text to be measured and the font of the text.

Hope I helped someone with this. Perhaps there is another way to do this, I found this answer by Hans Passant that truncates ToolTipStatusLabel, which is quite impressive. My .NET skills are not close to Hans Passant anywhere, so I couldn’t convert this code to work with something like TextBox ... But if you succeeded or have another solution, I would love to see it! :)

+13
source share

I tested the Jordy code and compared the result with this code, there is no difference, they both crop / truncate quite well, but not very well in some cases, this may be the size measured by MeasureString() , is not accurate. I know that this code is just a simplified version, I publish it here if someone cares about it and uses it because it is short, and I tested: there is no difference in how exactly this code can crop / truncate string compared to Jordy code, Of course, its code is some kind of full version supporting 3 methods.

 public static class TextBoxExtension { public static void Trim(this TextBox text){ string txt = text.Text; if (txt.Length == 0 || text.Width == 0) return; int i = txt.Length; while (TextRenderer.MeasureText(txt + "...", text.Font).Width > text.Width) { txt = text.Text.Substring(0, --i); if (i == 0) break; } text.Text = txt + "..."; } //You can implement more methods such as receiving a string with font,... and returning the truncated/trimmed version. } 
0
source share

All Articles