I want to Justify text Like Below Link Image in label there have word justifications not a character currently my code is doing this. And i am using another fonts as well and it is a multi-language application so the text justification is work some times in English language only but i need another fonts too.
MyCode is below, Please check this.
public void Justify(System.Windows.Forms.Label label)
{
string text = label.Text;
string[] lines = text.Split(new[] { "\r\n" }, StringSplitOptions.None).Select(l => l.Trim()).ToArray();
List<string> result = new List<string>();
foreach (string line in lines)
{
result.Add(StretchToWidth(line, label));
}
label.Text = string.Join("\r\n", result);
}
It is call next function
private string StretchToWidth(string text, Label label)
{
if (text.Length < 2)
return text;
// A hair space is the smallest possible non-visible character we can insert
const char hairspace = '\u200A';
// If we measure just the width of the space we might get too much because of added paddings so we have to do it a bit differently
double basewidth = TextRenderer.MeasureText(text, label.Font).Width;
double doublewidth = TextRenderer.MeasureText(text + text, label.Font).Width;
double doublewidthplusspace = TextRenderer.MeasureText(text + hairspace + text, label.Font).Width;
double spacewidth = doublewidthplusspace - doublewidth;
//The space we have to fill up with spaces is whatever is left
double leftoverspace = label.Width - basewidth;
//Calculate the amount of spaces we need to insert
int approximateInserts = Math.Max(0, (int)Math.Floor(leftoverspace / spacewidth));
//Insert spaces
return InsertFillerChar(hairspace, text, approximateInserts);
}
and last is this.
private static string InsertFillerChar(char filler, string text, int inserts)
{
string result = "";
int inserted = 0;
for (int i = 0; i < text.Length; i++)
{
//Add one character of the original text
result += text[i];
//Only add spaces between characters, not at the end
if (i >= text.Length - 1) continue;
//Determine how many characters should have been inserted so far
int shouldbeinserted = (int)(inserts * (i + 1) / (text.Length - 1.0));
int insertnow = shouldbeinserted - inserted;
for (int j = 0; j < insertnow; j++)
result += filler;
inserted += insertnow;
}
return result;
}
Related
I think I am too dumb to solve this problem...
I have some formulas which need to be "translated" from one syntax to another.
Let's say I have a formula that goes like that (it's a simple one, others have many "Ceilings" in it):
string formulaString = "If([Param1] = 0, 1, Ceiling([Param2] / 0.55) * [Param3])";
I need to replace "Ceiling()" with "Ceiling(; 1)" (basically, insert "; 1" before the ")").
My attempt is to split the fomulaString at "Ceiling(" so I am able to iterate through the string array and insert my string at the correct index (counting every "(" and ")" to get the right index)
What I have so far:
//splits correct, but loses "CEILING("
string[] parts = formulaString.Split(new[] { "CEILING(" }, StringSplitOptions.None);
//splits almost correct, "CEILING(" is in another group
string[] parts = Regex.Split(formulaString, #"(CEILING\()");
//splits almost every letter
string[] parts = Regex.Split(formulaString, #"(?=[(CEILING\()])");
When everything is done, I concat the string so I have my complete formula again.
What do I have to set as Regex pattern to achieve this sample? (Or any other method that will help me)
part1 = "If([Param1] = 0, 1, ";
part2 = "Ceiling([Param2] / 0.55) * [Param3])";
//part3 = next "CEILING(" in a longer formula and so on...
As I mention in a comment, you almost got it: (?=Ceiling). This is incomplete for your use case unfortunately.
I need to replace "Ceiling()" with "Ceiling(; 1)" (basically, insert "; 1" before the ")").
Depending on your regex engine (for example JS) this works:
string[] parts = Regex.Split(formulaString, #"(?<=Ceiling\([^)]*(?=\)))");
string modifiedFormula = String.join("; 1", parts);
The regex
(?<=Ceiling\([^)]*(?=\)))
(?<= ) Positive lookbehind
Ceiling\( Search for literal "Ceiling("
[^)] Match any char which is not ")" ..
* .. 0 or more times
(?=\)) Positive lookahead for ")", effectively making us stop before the ")"
This regex is a zero-assertion, therefore nothing is lost and it will cut your strings before the last ")" in every "Ceiling()".
This solution would break whenever you have nested "Ceiling()". Then your only solution would be writing your own parser for the same reasons why you can't parse markup with regex.
Regex.Replace(formulaString, #"(?<=Ceiling\()(.*?)(?=\))","$1; 1");
Note: This will not work for nested "Ceilings", but it does for Ceiling(), It will also not work fir Ceiling(AnotherFunc(x)). For that you need something like:
Regex.Replace(formulaString, #"(?<=Ceiling\()((.*\((?>[^()]+|(?1))*\))*|[^\)]*)(\))","$1; 1$3");
but I could not get that to work with .NET, only in JavaScript.
This is my solution:
private string ConvertCeiling(string formula)
{
int ceilingsCount = formula.CountOccurences("Ceiling(");
int startIndex = 0;
int bracketCounter;
for (int i = 0; i < ceilingsCount; i++)
{
startIndex = formula.IndexOf("Ceiling(", startIndex);
bracketCounter = 0;
for (int j = 0; j < formula.Length; j++)
{
if (j < startIndex) continue;
var c = formula[j];
if (c == '(')
{
bracketCounter++;
}
if (c == ')')
{
bracketCounter--;
if (bracketCounter == 0)
{
// found end
formula = formula.Insert(j, "; 1");
startIndex++;
break;
}
}
}
}
return formula;
}
And CountOccurence:
public static int CountOccurences(this string value, string parameter)
{
int counter = 0;
int startIndex = 0;
int indexOfCeiling;
do
{
indexOfCeiling = value.IndexOf(parameter, startIndex);
if (indexOfCeiling < 0)
{
break;
}
else
{
startIndex = indexOfCeiling + 1;
counter++;
}
} while (true);
return counter;
}
I am looking a way to create a HyperLink in a RichTextBox pointing to a line of the text of the same RichTextBox.
I just found how to do that with Internet Links but I don't find a way to do it with the same text inside of the control (It's like Hyperlinks in MS Word pointing to a header or bookmark).
Thanks in Advance. - CCB
No, this will not work unless you code the necessary stuff yourself.
Two suggestions:
A simple workaround with links always starting with www.
The nicer solution with arbitrary link text
Let's have a look at both options..:
Using the built-in functionality of recognizing an URL seems the right way to start, but the link will always have to look like a URL, not like a hyperlink to an anchor.. If you can live with a solution that has, say, links like this: www.goto.234 and anchors like this: #234# this is really rather simple..
A working example can be as simple as this:
private void richTextBox1_LinkClicked(object sender, LinkClickedEventArgs e)
{
var s = e.LinkText.Split('.');
string anchor = s[2];
int a = richTextBox1.Text.IndexOf("#" + anchor + "#" );
if (a >= 0) richTextBox1.SelectionStart = a; else return; // do add more checks!
richTextBox1.SelectionLength = 0;
Text = anchor + " # " + a;
//richTextBox1.ScrollToCaret(); <<--- this crashes on my machine!
// so I take the jump out of the click event and it works:
Timer ttt = new Timer() { Interval = 100 };
ttt.Tick += (ss, ee) => { richTextBox1.ScrollToCaret(); ttt.Stop(); };
}
Option two: If you'd rather have more choice of how the links should read you can do this:
Start by formatting each to
Start with a special character, say a tilde '~'
format it to look blue and underlined if you want to
Either make it one word or replace space by underlines and format those to have the forecolor equal to the backcolor
Now this can do the job:
public string delimiters = " ()[]{}!&?=/\\,;.\r\n";
private void richTextBox2_Click(object sender, EventArgs e)
{
int sstart = -1;
string s = getWordAt(richTextBox2.Text,
richTextBox2.SelectionStart, delimiters, out sstart);
if (s.Length < 3) return;
string char1 = s.Substring(0, 1);
if (char1 == "~")
{
int p = richTextBox2.Text.IndexOf("#" + s.Substring(1));
if (p >= 0) { richTextBox2.SelectionStart = p; richTextBox2.ScrollToCaret(); }
}
}
public static string getWordAt(string text, int cursorPos,
string delimiters, out int selStart)
{
int startPos = 0;
selStart = startPos;
if ((cursorPos < 0) | (cursorPos > text.Length) | (text.Length == 0)) return "";
if ((text.Length > cursorPos) & (delimiters.Contains(text[cursorPos]))) return "";
int endPos = text.Length - 1;
if (cursorPos == text.Length) endPos = text.Length - 1;
else { for (int i = cursorPos; i < text.Length; i++)
{ if (delimiters.Contains(text[i])) { endPos = i - 1; break; } } }
if (cursorPos == 0) startPos = 0;
else { for (int i = cursorPos; i > 0; i--)
{ if (delimiters.Contains(text[i])) { startPos = i + 1; break; } } }
selStart = startPos;
return text.Substring(startPos, endPos - startPos + 1);
}
Here are the two versions side by side, once at the top then after clicking on a link:
Both versions work fine, although both could do with some more checks.
Note that I was too lazy to format the pseudo-links in the second example, so they show their tildes and hashes..
Not hard to write a helper function that can insert the formatting; the search will still work as it searches in the Text, not the Rtf property..
I am writing out a large string (around 100 lines) to a text file, and would like the entire block of text tabbed.
WriteToOutput("\t" + strErrorOutput);
The line I am using above only tabs the first line of the text. How can I indent/tab the entire string?
Replace all linebreaks by linebreak followed by a tab:
WriteToOutput("\t" + strErrorOutput.Replace("\n", "\n\t"));
File.WriteAllLines(FILEPATH,input.Split(new string[] {"\n","\r"}, StringSplitOptions.None)
.Select(x=>"\t"+x));
To do so you would have to have a limited line length (ie <100 characters) at which point this issue becomes easy.
public string ConvertToBlock(string text, int lineLength)
{
string output = "\t";
int currentLineLength = 0;
for (int index = 0; index < text.Length; index++)
{
if (currentLineLength < lineLength)
{
output += text[index];
currentLineLength++;
}
else
{
if (index != text.Length - 1)
{
if (text[index + 1] != ' ')
{
int reverse = 0;
while (text[index - reverse] != ' ')
{
output.Remove(index - reverse - 1, 1);
reverse++;
}
index -= reverse;
output += "\n\t";
currentLineLength = 0;
}
}
}
}
return output;
}
This will convert any text into a block of text that is broken up into lines of length lineLength and that all start with a tab and end with a newline.
You could make a copy of your string for output that replaces CRLF with CRLF + TAB. And the write that string to output (still prefixed with the initial TAB).
strErrorOutput = strErrorOutput.Replace("\r\n", "\r\n\t");
WriteToOutput("\t" + strErrorOutput);
If you're here looking for a way to word-wrap a string to a certain width, and have each line indented (as I was), here's a solution as an extension method. Roughly based on the answer above, but uses regular expressions to split the original text into word and spaces pairs, then rejoins them, adding line breaks and indentation as needed. (Does not sanity check inputs, so you'll need to add that if needed)
public string ToBlock(this string text, int lineLength, string indent="")
{
var r = new Regex("([^ ]+)?([ ]+)?");
var matches = r.Match(text);
if (!matches.Success)
{
return text;
}
string output = indent;
int currentLineLength = indent.Length;
while (matches.Success)
{
var groups = matches.Groups;
var nextLength = groups[0].Length;
if (currentLineLength + nextLength <= lineLength)
{
output += groups[0];
currentLineLength += groups[0].Length;
}
else
{
if (currentLineLength + groups[1].Length > lineLength)
{
output += "\n" + indent + groups[0];
currentLineLength = indent.Length + groups[0].Length;
}
else
{
output += groups[1] + "\n" + indent;
currentLineLength = indent.Length;
}
}
matches = matches.NextMatch();
}
return output;
}
I need to write different paragraphs of text within a certain area. For instance, I have drawn a box to the console that looks like this:
/----------------------\
| |
| |
| |
| |
\----------------------/
How would I write text within it, but wrap it to the next line if it gets too long?
Split on last space before your row length?
int myLimit = 10;
string sentence = "this is a long sentence that needs splitting to fit";
string[] words = sentence.Split(new char[] { ' ' });
IList<string> sentenceParts = new List<string>();
sentenceParts.Add(string.Empty);
int partCounter = 0;
foreach (string word in words)
{
if ((sentenceParts[partCounter] + word).Length > myLimit)
{
partCounter++;
sentenceParts.Add(string.Empty);
}
sentenceParts[partCounter] += word + " ";
}
foreach (string x in sentenceParts)
Console.WriteLine(x);
UPDATE (the solution above lost the last word in some cases):
int myLimit = 10;
string sentence = "this is a long sentence that needs splitting to fit";
string[] words = sentence.Split(' ');
StringBuilder newSentence = new StringBuilder();
string line = "";
foreach (string word in words)
{
if ((line + word).Length > myLimit)
{
newSentence.AppendLine(line);
line = "";
}
line += string.Format("{0} ", word);
}
if (line.Length > 0)
newSentence.AppendLine(line);
Console.WriteLine(newSentence.ToString());
Here's one that is lightly tested and uses LastIndexOf to speed things along (a guess):
private static string Wrap(string v, int size)
{
v = v.TrimStart();
if (v.Length <= size) return v;
var nextspace = v.LastIndexOf(' ', size);
if (-1 == nextspace) nextspace = Math.Min(v.Length, size);
return v.Substring(0, nextspace) + ((nextspace >= v.Length) ?
"" : "\n" + Wrap(v.Substring(nextspace), size));
}
I started with Jim H.'s solution and end up with this method. Only problem is if text has any word that longer than limit. But works well.
public static List<string> GetWordGroups(string text, int limit)
{
var words = text.Split(new string[] { " ", "\r\n", "\n" }, StringSplitOptions.None);
List<string> wordList = new List<string>();
string line = "";
foreach (string word in words)
{
if (!string.IsNullOrWhiteSpace(word))
{
var newLine = string.Join(" ", line, word).Trim();
if (newLine.Length >= limit)
{
wordList.Add(line);
line = word;
}
else
{
line = newLine;
}
}
}
if (line.Length > 0)
wordList.Add(line);
return wordList;
}
I modified the version of Jim H such that it supports some special cases.
For example the case when the sentence does not contain any whitespace character; I also noted that there is a problem when a line has a space at the last position; then the space is added at the end and you end up with one character too much.
Here is my version just in case someone is interested:
public static List<string> WordWrap(string input, int maxCharacters)
{
List<string> lines = new List<string>();
if (!input.Contains(" "))
{
int start = 0;
while (start < input.Length)
{
lines.Add(input.Substring(start, Math.Min(maxCharacters, input.Length - start)));
start += maxCharacters;
}
}
else
{
string[] words = input.Split(' ');
string line = "";
foreach (string word in words)
{
if ((line + word).Length > maxCharacters)
{
lines.Add(line.Trim());
line = "";
}
line += string.Format("{0} ", word);
}
if (line.Length > 0)
{
lines.Add(line.Trim());
}
}
return lines;
}
This is a more complete and tested solution.
The bool overflow parameter specifies, whether long words are chunked in addition to splitting up by spaces.
Consecutive whitespaces, as well as \r, \n, are ignored and collapsed into one space.
Edge cases are throughfully tested
public static string WrapText(string text, int width, bool overflow)
{
StringBuilder result = new StringBuilder();
int index = 0;
int column = 0;
while (index < text.Length)
{
int spaceIndex = text.IndexOfAny(new[] { ' ', '\t', '\r', '\n' }, index);
if (spaceIndex == -1)
{
break;
}
else if (spaceIndex == index)
{
index++;
}
else
{
AddWord(text.Substring(index, spaceIndex - index));
index = spaceIndex + 1;
}
}
if (index < text.Length) AddWord(text.Substring(index));
void AddWord(string word)
{
if (!overflow && word.Length > width)
{
int wordIndex = 0;
while (wordIndex < word.Length)
{
string subWord = word.Substring(wordIndex, Math.Min(width, word.Length - wordIndex));
AddWord(subWord);
wordIndex += subWord.Length;
}
}
else
{
if (column + word.Length >= width)
{
if (column > 0)
{
result.AppendLine();
column = 0;
}
}
else if (column > 0)
{
result.Append(" ");
column++;
}
result.Append(word);
column += word.Length;
}
}
return result.ToString();
}
I modified Manfred's version. If you put a string with the '\n' character in it, it will wrap the text strangely because it will count it as another character. With this minor change all will go smoothly.
public static List<string> WordWrap(string input, int maxCharacters)
{
List<string> lines = new List<string>();
if (!input.Contains(" ") && !input.Contains("\n"))
{
int start = 0;
while (start < input.Length)
{
lines.Add(input.Substring(start, Math.Min(maxCharacters, input.Length - start)));
start += maxCharacters;
}
}
else
{
string[] paragraphs = input.Split('\n');
foreach (string paragraph in paragraphs)
{
string[] words = paragraph.Split(' ');
string line = "";
foreach (string word in words)
{
if ((line + word).Length > maxCharacters)
{
lines.Add(line.Trim());
line = "";
}
line += string.Format("{0} ", word);
}
if (line.Length > 0)
{
lines.Add(line.Trim());
}
}
}
return lines;
}
Other answers didn't consider East Asian languages, which don't use space to break words.
In general, a sentence in East Asian languages can be wrapped in any position between characters, except certain punctuations (it is not a big problem even if ignore punctuation rules). It is much simpler than European languages but when consider mixing different languages, you have to detect the language of each character by checking the Unicode table, and then apply the break lines by space algorithm only for European languages parts.
References:
https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap
https://en.wikipedia.org/wiki/Line_breaking_rules_in_East_Asian_languages
https://en.wikibooks.org/wiki/Unicode/Character_reference/0000-0FFF
This code will wrap the paragraph text. It will break the paragraph text into lines. If it encounters any word which is even larger than the line length, it will break the word into multiple lines too.
private const int max_line_length = 25;
private string wrapLinesToFormattedText(string p_actual_string) {
string formatted_string = "";
int available_length = max_line_length;
string[] word_arr = p_actual_string.Trim().Split(' ');
foreach (string w in word_arr) {
string word = w;
if (word == "") {
continue;
}
int word_length = word.Length;
//if the word is even longer than the length that the line can have
//the large word will get break down into lines following by the successive words
if (word_length >= max_line_length)
{
if (available_length > 0)
{
formatted_string += word.Substring(0, available_length) + "\n";
word = word.Substring(available_length);
}
else
{
formatted_string += "\n";
}
word = word + " ";
available_length = max_line_length;
for (var count = 0;count<word.Length;count++) {
char ch = word.ElementAt(count);
if (available_length==0) {
formatted_string += "\n";
available_length = max_line_length;
}
formatted_string += ch;
available_length--;
}
continue;
}
if ((word_length+1) <= available_length)
{
formatted_string += word+" ";
available_length -= (word_length+1);
continue;
}
else {
available_length = max_line_length;
formatted_string += "\n"+word+" " ;
available_length -= (word_length + 1);
continue;
}
}//end of foreach loop
return formatted_string;
}
//end of function wrapLinesToFormattedText
Blockquote
Here is a small piece of optimized code for wrapping text according to float sentence length limit written in Visual Basic9.
Dim stringString = "Great code! I wish I could found that when searching for Print Word Wrap VB.Net and other variations when searching on google. I’d never heard of MeasureString until you guys mentioned it. In my defense, I’m not a UI programmer either, so I don’t feel bad for not knowing"
Dim newstring = ""
Dim t As Integer = 1
Dim f As Integer = 0
Dim z As Integer = 0
Dim p As Integer = stringString.Length
Dim myArray As New ArrayList
Dim endOfText As Boolean = False REM to exit loop after finding the last words
Dim segmentLimit As Integer = 45
For t = z To p Step segmentLimit REM you can adjust this variable to fit your needs
newstring = String.Empty
newstring += Strings.Mid(stringString, 1, 45)
If Strings.Left(newstring, 1) = " " Then REM Chr(13) doesn't work, that's why I have put a physical space
newstring = Strings.Right(newstring, newstring.Length - 1)
End If
If stringString.Length < 45 Then
endOfText = True
newstring = stringString
myArray.Add(newstring) REM fills the last entry then exits
myArray.TrimToSize()
Exit For
Else
stringString = Strings.Right(stringString, stringString.Length - 45)
End If
z += 44 + f
If Not Strings.Right(newstring, 1) = Chr(32) Then REM to detect space
Do Until Strings.Right(newstring, z + 1) = " "
If Strings.Right(newstring, z + f) = " " OrElse Strings.Left(stringString, 1) = " " Then
Exit Do
End If
newstring += Strings.Left(stringString, 1)
stringString = Strings.Right(stringString, stringString.Length - 1) REM crops the original
p = stringString.Length REM string from left by 45 characters and additional characters
t += f
f += 1
Loop
myArray.Add(newstring) REM puts the resulting segments of text in an array
myArray.TrimToSize()
newstring = String.Empty REM empties the string to load the next 45 characters
End If
t = 1
f = 1
Next
For Each item In myArray
MsgBox(item)
'txtSegmentedText.Text &= vbCrLf & item
Next
I know I am a bit late, But I managed to get a solution going by using recursion.
I think its one of the cleanest solutions proposed here.
Recursive Function:
public StringBuilder TextArea { get; set; } = new StringBuilder();
public void GenerateMultiLineTextArea(string value, int length)
{
// first call - first length values -> append first length values, remove first length values from value, make second call
// second call - second length values -> append second length values, remove first length values from value, make third call
// third call - value length is less then length just append as it is
if (value.Length <= length && value.Length != 0)
{
TextArea.Append($"|{value.PadRight(length)}" + "|");
}
else
{
TextArea.Append($"|{value.Substring(0, length).ToString()}".PadLeft(length) + "|\r\n");
value = value.Substring(length, (value.Length) - (length));
GenerateMultiLineTextArea(value, length);
}
}
Usage:
string LongString =
"This is a really long string that needs to break after it reaches a certain limit. " +
"This is a really long string that needs to break after it reaches a certain limit." + "This is a really long string that needs to break after it reaches a certain limit.";
GenerateMultiLineTextArea(LongString, 22);
Console.WriteLine("/----------------------\\");
Console.WriteLine(TextArea.ToString());
Console.WriteLine("\\----------------------/");
Outputs:
/----------------------\
|This is a really long |
|string that needs to b|
|reak after it reaches |
|a certain limit. This |
|is a really long strin|
|g that needs to break |
|after it reaches a cer|
|tain limit.This is a r|
|eally long string that|
| needs to break after |
|it reaches a certain l|
|imit. |
\----------------------/
I have a Listbox in a SplitterPanel. I have overriden it's MeasureItem() and DrawItem() methods.
What I want to do is, depending on Listbox.Width, return either the entire string or a shortened version of it, like "Dance toni...".
I've browsed SO and found two questions that pertain to my problem. One of the problems is measuring the width of the text, which I am doing with e.Graphics.MeasureString() in DrawItem().
Summary - I have the width of a listbox, and the width, in pixels, of a string. If the string is shorter than the width of a listbox, I want to display the string in entirety. However, if it's longer, I would like to return a version like "Hello every..." that would fit in within the width of the listbox.
So far I have:
private string FitText(string s)
{
int width = (TextRenderer.MeasureText(s, titleFont)).Width;
if (width <= mailList.Width)
{
return s;
}
else if (width > mailList.Width)
{
// What goes here?
}
}
I'm pretty sure it's just simple math, but I still can't figure it out.
i think you would need check if it fits, if so, return the whole string, otherwise modify your code to run a loop that keeps measuring the size of s minus one more character and plus the ellipsis, until it fits or until there are no more characters left, and then return that, or just the ellipsis otherwise.
string EllipsisString = "..."; // you could also just set this as the unicode ellipsis char if that displays properly
private string FitText(string s)
{
bool WidthFound = true;
string TestString = s;
string StringToReturn = s;
int width = (TextRenderer.MeasureText(s, titleFont)).Width;
if (width > mailList.Width)
{
WidthFound = false;
for (int i=1; i < s.Length; ++i)
{
TestString = s.Substring(0, s.Length - i) + EllipsisString;
width = (TextRenderer.MeasureText(TestString, titleFont)).Width;
if (width <= mailList.Width)
{
StringToReturn = TestString;
WidthFound = true;
break;
}
}
}
if (WidthFound)
return StringToReturn;
else
return EllipsisString;
}
[edits: too many to name]
Here's the pseudocode I'd use...
1) Shorten the string in some form (remove the last character/word)
2) Retest the length against width
3) Insert of valid repeat if not
4) If string is too short use some default form
String s = "A long string that you're trying to fit into the button."
while (width > mailList.Width) {
s = s.SubString(0,s.lastIndexOf(" ")-1); //Change this to whatever you'd want to shorten the string by
width = (TextRenderer.MeasureText(s, titleFont)).Width;
if (width < 5) { //Some value indicating it's too short
s = "Button...";
break;
}
}
return s;
http://msdn.microsoft.com/en-us/library/aa904308%28v=vs.71%29.aspx
string ts = s;
while((TextRenderer.MeasureText(ts, titleFont)).Width > mailList.Width + (TextRenderer.MeasureText("...", titleFont)).Width)
{
ts = ts.SubString(0,ts.Length-1);
}
return ts + "..."