Simulating a layout transform for text in Silverlight 2.0

Friday, January 23, 2009 by Vladimir Milev | Comments 3

The Telerik charting team is hard at work on making our WPF chart compatible with Silverlight. In the process we are faced with numerous limitations of SL. One of the more cunning problems I’ve faced was the fact that there are still no layout transforms available which leads to some wacky problems when you try to rotate text.

Let’s assume a very simple layout consisting of a single grid with two columns, one with width=”auto”  and the other with width=”*”. The first column contains a string of text. Here is how it looks before any transforms are applied:

<Grid x:Name="LayoutRoot" Background="SkyBlue">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="auto" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <ContentControl x:Name="ContentControl1" >
    </ContentControl>
    <Grid Background="Pink" Grid.Column="1"/>
</Grid>

rotate1

Now let’s try to rotate the text vertically:

<ContentControl x:Name="ContentControl1" >
    <ContentControl.RenderTransform>
        <RotateTransform Angle="-90" />
    </ContentControl.RenderTransform>
</ContentControl>

The resulting picture will be the following:

rotate2

Not quite what we expected, eh? Well, first of all the text is not gone. It really is rotated -90 degrees but since the layout of the gird panel did not change it was pushed out. You can see what happens if you try to rotate the text by smaller angles. Unfortunately all you have in Silverlight is the RenderTransform so we must use it if we want to rotate the text. But what can we do about the layout problem? Well, as it turns out we can write our own custom panel which will transpose the text width and height and position the string in a more appropriate way:

public class RotatePanel : Panel
    {
        protected override Size MeasureOverride(Size availableSize)
        {
            foreach (UIElement child in this.Children)
            {
                child.Measure(availableSize);
            }

            double maxWidth = this.Children.MaxOrDefault(child => child.DesiredSize.Width, 0);
            double maxHeight = this.Children.MaxOrDefault(child => child.DesiredSize.Height, 0);
           
            return new Size(maxHeight, maxWidth);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            foreach (UIElement child in this.Children)
            {
                child.Arrange(new Rect(0, (finalSize.Height / 2) + (child.DesiredSize.Width / 2), child.DesiredSize.Width, child.DesiredSize.Height));
            }

            return finalSize;
        }
    }

Now we just need to wrap our ContentPresenter with the magic panel and we’re good to roll:

<local:RotatePanel>
    <ContentControl x:Name="ContentControl1" >
        <ContentControl.RenderTransform>
            <RotateTransform Angle="-90" />
        </ContentControl.RenderTransform>
    </ContentControl>
</local:RotatePanel>
rotate3

Well that’s about it. Hope my rant didn’t bore you and helps someone out there.

Example Source Download

3 Comments

  • Sydney Peacock 25 Jan 2009
    What's the MaxOrDefault method do? Is it some proprietary method of telerik's?
    Cool post btw!
  • Tony Corneto 25 Jan 2009
    Charting controls are a critical area for us in considering licensing of Telerik controls for Silverlight.  I completely understand there are technical hurdles with the current limitations of Silverlight.  Do you still feel confident that you will be able to deliver the charting controls by the end of February?

    Thanks for all the hard work guys.  Everything looks great so far.

    Tony
  • Vladimir Milev 26 Jan 2009
    Sydney,
    Thanks for your comment! The MaxOrDefault method is actually a wrapper we've written over the standard Max method. You can check this blogpost for more info.

    Tony,
    We are currently on track for releasing charting for silverlight with the Q1 2009 release at the end of February.

Add comment

  1. Formatting options
       
     
     
     
     
       
  2. (optional, emails won't be shown on public pages)
  3. (optional)