When I have a place with limited space, where I entry a text that can be few letters or huge amount of text because it's dynamic, I'm using this code to make the text fit the specific space.
#region TextSizing
string textSizing = databaseTable.Description;
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromHwnd(IntPtr.Zero))
{
size = g.MeasureString(textSizing, new System.Drawing.Font("Arial", 14)).Width;
}
if (size < 1500)
lblText.Text = textSizing;
else
lblText.Text = textSizing.Length > 135 ? textSizing.Remove(135) + "..." : textSizing;
#endregion
A friend of mine suggested that I should use cache to store the Font and the Graphics, I didn't understand it very well, but keep thinking about it... How can I make this code (that is usually in a loop) faster and efficiently ?
1 Answer 1
Cache the instance of Graphics
and Font
objects so that you don't need to create them each time you measure the length of string. I've created a small test to see which part takes most of the time:
private static void Main()
{
Stopwatch stopwatch = Stopwatch.StartNew();
stopwatch.Restart();
for (int i = 0; i < 1000000; i++)
{
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromHwnd(IntPtr.Zero))
{
var size = g.MeasureString("asdasdf", new System.Drawing.Font("Arial", 14)).Width;
}
}
Console.WriteLine("Current solution - create a new Graphics per measure: {0} milliseconds", stopwatch.ElapsedMilliseconds);
stopwatch.Restart();
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromHwnd(IntPtr.Zero))
{
for (int i = 0; i < 1000000; i++)
{
var size = g.MeasureString("asdasdf", new System.Drawing.Font("Arial", 14)).Width;
}
}
Console.WriteLine("Measure the string with Graphics cached: {0} milliseconds", stopwatch.ElapsedMilliseconds);
stopwatch.Restart();
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromHwnd(IntPtr.Zero))
using (var font = new System.Drawing.Font("Arial", 14))
{
for (int i = 0; i < 1000000; i++)
{
var size = g.MeasureString("asdasdf", font).Width;
}
}
Console.WriteLine("Measure the string with Graphics and font cached: {0} milliseconds", stopwatch.ElapsedMilliseconds);
}
Results on my computer are:
Current solution - create a new Graphics per measure: 26864 milliseconds
Measure the string with Graphics cached: 6588 milliseconds
Measure the string with Graphics and font cached: 803 milliseconds
So by caching Graphics
you'll reduce the time consumption by 75%, and by caching both Font
and Graphics
you get a nice 33.5X performance boost :).
-
\$\begingroup\$ Thank you very much for your hard work. This help me more than I expected =) \$\endgroup\$Michel Ayres– Michel Ayres2012年12月12日 16:33:16 +00:00Commented Dec 12, 2012 at 16:33
-
\$\begingroup\$ Now I just need to figure out a way to do this as a method. \$\endgroup\$Michel Ayres– Michel Ayres2012年12月12日 16:37:36 +00:00Commented Dec 12, 2012 at 16:37
-
1\$\begingroup\$ @MichelAyres see updated answer for better results :) \$\endgroup\$almaz– almaz2012年12月12日 17:17:29 +00:00Commented Dec 12, 2012 at 17:17
...
, and not three dots. You might also be interested in gist.github.com/4250125 \$\endgroup\$