I am attempting to create an onscreen keyboard using a Grid for key layout. Each key consists of a Border with a TextBlock containing a letter. To make the letters scale I have wrapped each TextBlock in a ViewBox, for example;
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="0">
<Border BorderThickness="1" BorderBrush="Gray">
<Viewbox>
<TextBlock Text="a" />
</Viewbox>
</Border>
</Grid>
<Grid Grid.Row="0" Grid.Column="1">
<Border BorderThickness="1" BorderBrush="Gray">
<Viewbox>
<TextBlock Text="b" />
</Viewbox>
</Border>
</Grid>
<Grid Grid.Row="0" Grid.Column="2">
<Border BorderThickness="1" BorderBrush="Gray">
<Viewbox>
<TextBlock Text="c" />
</Viewbox>
</Border>
</Grid>
</Grid>
The problem is when you shrink the control by resizing the window horizontally (i.e. squash the borders together horizontally). As each letter has a slightly different width and height, the amount of zooming/scaling applied by each viewbox is not exactly the same. This results in the letters being rendered at different vertical heights, i.e. the "b" will be on a horizontal plane above the "a" and "c", which looks a little wrong.
The only work around I can think of (which works) relies on fixing the widths of each textblock, e.g. setting Width="10". This, however, feels unsatisfactory as it requires knowledge of the font which will be used to display each letter and an assumption about the maximum width. A middle ground would be to achieve this automatically the largest possible letter/glyph in each viewbox by including a hidden letter in each textblock;
<Grid Grid.Row="0" Grid.Column="0">
<Border BorderThickness="1" BorderBrush="Gray">
<Viewbox>
<Grid>
<TextBlock Text="a" />
<TextBlock Text="X" Visibility="Hidden" />
</Grid>
</Viewbox>
</Border>
</Grid>
I don't like that solution though and would love a reliable way to ensure all textblocks are the same size and so scale acceptably, without hard coding values or assumptions about the font.
Any ideas?
Thanks.
This MSDN question is answered correctly; http://social.msdn.microsoft.com/Forums/vstudio/en-US/c052fa89-4788-4d85-b266-fdd5c637a0ff/sharing-viewbox-zoom-level-between-items?forum=wpf
The solution relies on leveraging the SharedSizeGroup behaviour on a grid to ensure that the viewbox of every key is the same size as every other viewbox, like so;
<Viewbox>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="col"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition SharedSizeGroup="row"/>
</Grid.RowDefinitions>
<TextBlock Text="a" />
</Grid>
</Viewbox>
Other solutions involving hard coding the width/height of the viewbox, or binding to a common viewbox and filling it with the largest possible glyph work, but are not perfect solutions. The above solution makes no assumptions and relies on built in WPF measure/arrange logic to produce the desired outcome.