Creating a Silverlight Layout Panel

On our current project, we came across the need to build some custom layout panels in Silverlight to achieve some complex fluid layouts that we could not get from the built in controls. I was amazed to see how easy it was to create your own. This panel that I’m going to show is nothing fancy, but it shows how simple it really is. It will layout it’s children in a diagonal direction from upper left to lower right.

The first thing we need to do is create a new class and inherit from Panel. Panel is the base class for the built-in layout controls such as Grid and StackPanel.

public class DiagonalStackPanel : Panel
{
}

The next thing is to override the MeasureOverride() method. In this method you should iterate through the Children collection and call the Measure() method on each child. After Measure() is called, the DesiredSize property of the child will be populated with the size in which the child wants to be rendered.

protected override Size MeasureOverride(Size availableSize)
{
    double totalWidth = 0;
    double totalHeight = 0;

    foreach (var child in Children)
    {
        child.Measure(availableSize);

        totalWidth += child.DesiredSize.Width;
        totalHeight += child.DesiredSize.Height;
    }

    return new Size(totalWidth, totalHeight);
}

You can see that we’re adding up all the widths and heights of each child and returning the size (desired) for our Panel.

Next we override the ArrangeOverride() method. This is where we actually layout the children in the diagonal pattern. We do that by calculating the running total sizes of the child controls and calling Arrange() on each child with the appropriate sizing Rect object.

protected override Size ArrangeOverride(Size finalSize)
{
    double runningWidth = 0;
    double runningHeight = 0;

    foreach (var child in Children)
    {
        var width = child.DesiredSize.Width;
        var height = child.DesiredSize.Width;

        var finalRect = new Rect(runningWidth, runningHeight, width, height);
        child.Arrange(finalRect);

        runningWidth += width;
        runningHeight += height;
    }

    return new Size(runningWidth, runningHeight);
}

Now we can use our panel like so:

<UserControl x:Class="LayoutPanelExample.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:c="clr-namespace:LayoutPanelExample">
    <Grid x:Name="LayoutRoot" Background="White">
        <c:DiagonalStackPanel>
            <Button Content="Button"/>
            <Button Content="Button"/>
            <Button Content="Button"/>
            <Button Content="Button"/>
            <Button Content="Button"/>
            <Button Content="Button"/>
        </c:DiagonalStackPanel>
    </Grid>
</UserControl>

and we’ll get something that looks like:

image

You could extend this by added Dependency Properties to the panel so that you can customize how each child reacts in the layout. This is how the Grid works. It looks at the properties set on the child elements and figures out what row and column to place them in.

Technorati Tags: ,

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Ray Houston

Ray is a software development leader and architect with 20 years hands-on experience. He enjoys finding elegant solutions to complex problems and delivering real value to customers. Ray is a speaker and contributor to community events.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

3 Responses to Creating a Silverlight Layout Panel

  1. EdTaupier says:

    Great! Thanks for the example. I’m just starting to play with WPF and this definitely got my psyched about the potential. Keep ‘em comin’

  2. GC says:

    Thanks for the excellent example.

  3. Adriana says:

    Hello!
    I am creating a new LinearLayout class which inherites from Panel, and I am using meassureoverride, but the desiredSize field of the element doesn’t change.. Is there anything I can do to set desiredSize?

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>