Using WPF, what is the most efficient way to measure a large number of short strings? Specifically, I\'d like to determine the display height of each string, given uniform
The most low-level technique (and therefore giving the most scope for creative optimisations) is to use GlyphRuns.
It's not very well documented but I wrote up a little example here:
http://smellegantcode.wordpress.com/2008/07/03/glyphrun-and-so-forth/
The example works out the length of the string as a necessary step before rendering it.
You can use the DesiredSize property on a rendered TextBox to get the height and width
using System.Windows.Threading;
...
Double TextWidth = 0;
Double TextHeight = 0;
...
MyTextBox.Text = "Words to measure size of";
this.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new DispatcherOperationCallback(delegate(Object state) {
var size = MyTextBox.DesiredSize;
this.TextWidth = size.Width;
this.TextHeight = size.Height;
return null;
}
) , null);
If you have a large number of strings it may be quicker to first pre-calualte the height and width of every indiviudal letter and symbol in a given font, and then do a calculation based on the string chars. This may not be 100% acurate due to kerning etc
In WPF:
Remember to call Measure() on the TextBlock before reading the DesiredSize property.
If the TextBlock was created on-the-fly, and not yet shown, you have to call Measure() first, like so:
MyTextBlock.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
return new Size(MyTextBlock.DesiredSize.Width, MyTextBlock.DesiredSize.Height);
In Silverlight:
No need to measure.
return new Size(TextBlock.ActualWidth, TextBlock.ActualHeight);
The complete code looks like this:
public Size MeasureString(string s) {
if (string.IsNullOrEmpty(s)) {
return new Size(0, 0);
}
var TextBlock = new TextBlock() {
Text = s
};
#if SILVERLIGHT
return new Size(TextBlock.ActualWidth, TextBlock.ActualHeight);
#else
TextBlock.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
return new Size(TextBlock.DesiredSize.Width, TextBlock.DesiredSize.Height);
#endif
}
It is very simple and done by FormattedText class! Try it.