This is the first part of a multi-part panel series. One of the areas that I was so impressed with WPF and Silverlight was the power of the layout system. An element’s layout is truly decoupled from the visual rendering of elements and as WPF/Silverlight developers we wield full control over that through something called a Panel.

A panel is responsible for two things. First, determining size through measurement and second, determining positioning through arrangement. These are exposed through methods called MeasureOverride and ArrangeOverride and are available when you inherit from the Panel class.

Below is an Arrange Override method that I wrote for an Ellipse Panel. Things to note are that I have some properties defined on my Panel that I am using. HorizontalScalar and VerticalScalar for the Width and Height of my Ellipse. Funny names, miainly because a Panel, as a UIElement already has a Width and Height, so to avoid confusion, there you go.

protected override Size ArrangeOverride(Size finalSize)
{
    Size returnSize = base.ArrangeOverride(finalSize);
    double count = 1;
    if(this.Children.Count != 0) 
    {
        count = Children.Count;
    }
    double angleIncrement = 360 / count;
    for (int i = 0; i < this.Children.Count; i++)
    {
        double centerX = (returnSize.Width / 2) - (CalculateAverageItemWidth() / 2);
        double centerY = (returnSize.Height / 2) - (CalculateAverageItemHeight() / 2);
        
        double angleDeg = -90 + i * angleIncrement;
        double angle = angleDeg * (Math.PI / 180.0);
        UIElement element = this.Children[i] as UIElement;
        
        double x = centerX + HorizontalScalar * Math.Cos(angle);
        double y = centerY + VerticalScalar * Math.Sin(angle);

        Rect r = new Rect(x, y, element.DesiredSize.Width, element.DesiredSize.Height);

        element.Arrange(r);

    }
    return returnSize;
}

Positioning, that’s great. What’s next?

So is that it, right? Well not really. We can also inject some interesting effects on our elements by applying render transformations on them. Since we already have a nice autonomous bit of presentation logic this seems like the appropriate place to add affects like that. In my ellipse panel, I added a property that will basically change the rotation of elements to be facing up and down vs. relative outward.

double rotateAngle = 0;
if (AllowItemRotation)
{
    rotateAngle = ItemRotationOffset + angleDeg;
}

System.Windows.Media.RotateTransform tran = new System.Windows.Media.RotateTransform();
tran.Angle = rotateAngle;
element.RenderTransform = tran;
element.RenderTransformOrigin = new Point(0.5, 0.5);

As you can see now we have a much more non-desktop feel. We have effectively made this panel useful in both Vertically oriented displays and horizontally oriented displays (such as the Microsoft Surface). Now that is versatility!