Posterous theme by Cory Watilo

Filed under: richtextbox

Silverlight 4 font woes

This may or may not be a specific RichTextBox problem so I'm going to treat it like it is not.

The situation is that I'm displaying a document with text that can specify any font that it desires.  Of course, you cannot display text in a font that isn't installed.  Silverlight 4 does not give any kind of font list by font name.

Wait! Fonts.SystemFontFaces will give you a list of all fonts installed on the local system.  It will give you a list of font FILE NAMES.  Not a list of actual font names.  There does not seem to be anyway to translate a font file name to a font name.  So that's a big fat dead end.

Supposedly, Silverlight should just fall back on the system default which is "Portable User Interface" which is a best effort on Silverlight's part to display text.  That ought to be fine for me when I'm trying to display a font that isn't installed.

However, that isn't what happens for the RichTextBox.  What does happen is that the RichTextBox decides to have a CATASTROPHIC FAILURE in it's MeasureOverride method when trying to size up the box.  What seemingly happens is that the fallback mechanism just doesn't work.  I've specified a font that doesn't exist and Silverlight blows up.  Actually, it loops the exception for a while then throws up an unhandled crash box thing.  If I try to manually handle the error and give a reasonable size back, then it's an infinite loop :)

The solution is to manually specify a fallback font when I'm setting the FontFamily through code:

new FontFamily(formatting.FontName + ", " + TextFormatting.DefaultFontName);

DefaultFontName currently spits out "Arial" which is no good for non-latin languages.  So I'll have to solve that later.  I had hoped I could simply put "Portable User Interface" to be the default but that doesn't work at all.

If anyone knows of anything better, please comment.

 

Adventures in Silverlight 4: Richtextboxes and DataGrids

I've had to discover the wonders of the RichTextBox in Silverlight 4.  Here's the worst thing about it: it's practically all native code.  The stacktraces mean nothing as they usually soon disappear into a native call.  So breaking execution or looking at Reflector does not help much.

The RichTextBox control is also not quite there.  While I'm very thankful for how it handles many MANY languages.  I've ran into a few problems that are major bugs.  The biggest, by far, is one that only happens in very specific yet not uncommon cases.

The bug must be some infinite loop in native code (since I can't see anything happen when I break execution) since CPU maxes out when it happens.  To get this to happen, I have to do the following: put the RTB in a DataGrid to display text in the rows, make the RTB be in RightToLeft, use InlineUIContainers, then start sizing the browser window.  Certain cases cause the CPU to just spin in the MeasureOverride method with these conditions.

Another problem, specifically with the DataGrid itself, is that it's Rows don't auto-shrink.  There are tons of posts about it:

http://forums.silverlight.net/forums/p/160830/375007.aspx

http://forums.silverlight.net/forums/t/71184.aspx

http://forums.silverlight.net/forums/p/133177/299525.aspx

http://forums.silverlight.net/forums/p/123169/277437.aspx

The only reliable fixes for me, so far are:

A) Forcing a resizing of RowHeight programmatically:

datagrid1.RowHeight = 10;
            Dispatcher.BeginInvoke(delegate
            {
                datagrid1.RowHeight = double.NaN;
            });

B) Changing the CellStyle of the DataGrid to have the Template's root Grid have a Top VerticalAlignment.

Even if I report the RTB problem, it won't be fixed until SL5 or be ignored/unsolved just like the DataGrid row sizing.

 

Update:

Using the B strategy (which is the best because A uses way too many resources) you also need to listen to the SizeChanged event of the control in the row that should govern the size.  In my case, it is the RichTextBox.  On SizeChanged, you need to get the DataGridCellsPresenter and set the height of the Presenter to the ActualHeight of the control.  Like so:

 

 RichTextBox control = sender as RichTextBox;

 DataGridCell cell = control.Parent as DataGridCell;

 DataGridCellsPresenter presenter = cell.Parent as DataGridCellsPresenter;

 presenter.Height = control.ActualHeight;