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


About the Author

Vladimir Milev

Vladimir Milev is a developer manager.

Comments

Comments are disabled in preview mode.