Reputation: 273
I have a winform application on which I place a label. I change the text of the label dynamically from a background thread. The text change fires an event that is supposed to resize the label. Everything works fine except the string length I measure is incorrect and consequently the client size of the label is incorrect.
protected void progressInfo_TextChanged(object sender, EventArgs e)
{
// Auto size label to fit the text
// ... create a Graphics object for the label
Graphics g_progressInfo = this.progressInfo.CreateGraphics();
// ----------------
// Set up string.
string text1 = "Reading data from input data file ... inputData";
Font stringFont = new System.Drawing.Font("Verdana", 8,
System.Drawing.FontStyle.Regular);
Size textSize = TextRenderer.MeasureText(text1, stringFont);
TextRenderer.DrawText(g_progressInfo, text1, stringFont,
new Rectangle(new Point(10, 10), textSize), Color.Red);
System.Diagnostics.Debug.WriteLine("textSize = " + (textSize).ToString());
// ----------------
// Set the TextRenderingHint property.
g_progressInfo.TextRenderingHint =
System.Drawing.Text.TextRenderingHint.AntiAlias;
// ... get the Size needed to accommodate the formatted text
Size preferredSize_progressInfo = g_progressInfo.MeasureString(
this.progressInfo.Text, this.progressInfo.Font).ToSize();
System.Diagnostics.Debug.WriteLine("preferredSize_progressInfo = " +
(preferredSize_progressInfo).ToString());
/*
g_progressInfo.MeasureString above calculates the size of the string as floting
point numbers that get truncated by .ToSize().
... pad the text by 1 pixel, and resize the label
*/
System.Diagnostics.Debug.WriteLine("this.progressInfo.ClientSize = " +
(this.progressInfo.ClientSize).ToString());
this.progressInfo.ClientSize = new Size(
preferredSize_progressInfo.Width + 10, preferredSize_progressInfo.Height + 1);
System.Diagnostics.Debug.WriteLine("this.progressInfo.ClientSize = " +
(this.progressInfo.ClientSize).ToString());
// ... clean up the Graphics object
g_progressInfo.Dispose();
}
Here is the output from debugging:
Result from TextRenderer ---> textSize = {Width=270, Height=13}
Size calculated by MeasureString() ---> preferredSize_progressInfo = {Width=260, Height=14}
Initial label client size ---> progressInfo.ClientSize = {Width=100, Height=23}
Resized client size based on MeasureString ---> this.progressInfo.ClientSize = {Width=270, Height=15}
The issue is that the string widths calculated differ by 10 pixels. As it turns out, the width calculated by the TextRenderer, width = 270, is correct and the one calculated by MeasureString, width = 260, is incorrect because it truncates the display of the input string to: "Reading data from input data file ... input". I have also tried measuring the string width using MeasureCharacterRanges() and this approach yields a result similar to that produced by the MeasureString approach. The size calculated by TextRenderer seems to display the text correctly.
Yes, I understand that if this is the case I should simply use the TextRenderer, but can someone please explain to me the source of such a huge discrepancy in the string width calculated by the various methods? Any help or guidance would be greatly appreciated. Thank you.
Upvotes: 2
Views: 4182
Reputation: 273
I have actually found an answer to this. It was in an earlier post on stackoverflow titled TextRenderer.MeasureText and Graphics.MeasureString mismatch in size and was answered by Sven as follows:
TextRenderer uses GDI to render the text, whereas Graphics uses GDI+. The two use a slightly different method for laying out text so the sizes are different.
Which one you should use depends on what will eventually be used to actually draw the text. If you are drawing it with GDI+ Graphics.DrawString, measure using Graphics.MeasureString. If you are drawing using GDI TextRenderer.DrawText, measure using TextRenderer.MeasureText.
If the text will be displayed inside a Windows Forms control, it uses TextRenderer if UseCompatibleTextRendering is set to false (which is the default).
I wish to add that setting UseCompatibleTextRendering = true on my control improved the situation but did not completely resolve it. This time the input string was cut off at "Reading data from input data file ... inputDa". It would therefore appear that using TextRenderer is the way to go for Winform controls.
Upvotes: 1