2
\$\begingroup\$

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 ?

asked Dec 12, 2012 at 12:01
\$\endgroup\$
2
  • \$\begingroup\$ Not sure how to put a good title for this question, so please feel free to change it so it can be fit more the Q&A format. thanks. \$\endgroup\$ Commented Dec 12, 2012 at 12:02
  • 2
    \$\begingroup\$ You should use the unicode character ellipsis ..., and not three dots. You might also be interested in gist.github.com/4250125 \$\endgroup\$ Commented Dec 12, 2012 at 13:25

1 Answer 1

10
\$\begingroup\$

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 :).

answered Dec 12, 2012 at 16:09
\$\endgroup\$
3
  • \$\begingroup\$ Thank you very much for your hard work. This help me more than I expected =) \$\endgroup\$ Commented Dec 12, 2012 at 16:33
  • \$\begingroup\$ Now I just need to figure out a way to do this as a method. \$\endgroup\$ Commented Dec 12, 2012 at 16:37
  • 1
    \$\begingroup\$ @MichelAyres see updated answer for better results :) \$\endgroup\$ Commented Dec 12, 2012 at 17:17

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.