Today I came across an issue with the LongListSelector, part of the Silverlight for Windows Phone Toolkit. Solving the issue seemed pretty simple in the end, but first some background.
The LongListSelector is a control that can be used to create a list of groups. A good example of this is the contacts list in the people hub. In that list the contacts are organized based on the first letter of their name. Every group contains a header, in this case the first letter, and using this header you can very easily switch between groups. By using the LongListSelector from the toolkit, developers can create the same experiences in their apps.
The issue I encountered was the fact that I was getting ArgumentOutOfRange exceptions when an item was added to a group dynamically. This issue was supposed to be fixed in the November 2011 release, as stated in the release notes:
LongListSelector bug fixes around OutOfRange exceptions, wrong ordering of items, grouping issues, and scrolling events. ItemTuple is now refactored to be the public type LongListSelectorItem to provide users better access to the values in selection changed handlers.
Well this doesn't seem to be the case exactly. Most of those fixes were actually in changeset 71191 and 71199, which according to the codeplex site are included in the November release. This appears to be not so. When comparing some of the code in the installed Microsoft.Phone.Controls.Toolkit.dll to the source on codeplex it seems to be the case that the installed dll is compiled from a revision at least before 70993.
The solution is simple:
- Download the latest source from codeplex (this currently also includes some fixes to the PhoneTextBox, changeset 74775).
- Compile it.
- Use the resulting dll instead of the one installed by the toolkit.
Recently I came accross the issue where I wanted to limit the number of lines shown in my TextBlock on Windows Phone to for example 3. If the text was longer than 3 lines, the rest of the text should just not be shown. To do this I wanted to set the height of the TextBlock to a fixed height, to be exact 3 times the height of one line. This seems trivial, but to find the height of a line, you need to know something about the way Silverlight measures and calculates heights.
In Silverlight on the desktop and Silverlight for Windows Phone the measuring system is based on pixel units instead of Device Independent Pixel (DIP) units, as it is in WPF. Also the measuring system does not support unit measure string suffixes such as pt, cm or px. Silverlight measurements are always pixel units.
So if we specify the height of a Grid or a TextBlock to be 30 it actually is 30 pixel units. FontSize is no exception to this rule so when you specify 30 as the FontSize, you get a font that from the top of its ascenders to the bottom of its descenders measures approximately 36 pixels. Nevertheless the height of the corresonding TextBlock will be higher, because additional space is used to preserve space between successive lines. This concept is called leading.
In classical typography font sizes are expressed in units of points where a point is almost 1/72th of an inch. Digital typography assumes almost always a value of exactly 1/72th of an inch. This means that text with a font size of 72 points measures approximately 1 inch. Converting between pixels and points is difficult because it depends on the device you are using. Using a printer with 600 dpi (dots per inch) a font with size 72 will measure 600 pixels.
Windows assumes video displayes to have a dpi of 96. Using this assumption one can easily transform pixels into points and the other way around using the following two formulas:
points = 72/96 * pixels = 3/4 * pixels
pixels = 96/72 * points = 4/3 * points
Although Windows Phone screens have a much higher dpi than 96 these formulas also work for the phone. Suppose you want to set a 45 point font. Then you need to set the FontSize property to 60. On top of this Silverlight will add leading, which is approximately 33% of the size set as FontSize, which will result in the height of the TextBlock being 80 pixels.
It is possible to change this behavior by using the LineHeight and LineStackingStrategy properties of a TextBlock. You can read more about it here.