Creating a Custom Panel in Silverlight

Silverlight allows StackPanel and WrapPanel to be used as items panels in a ItemsPanelTemplate, for controls like ListBox where a collection of items are shown.

Sometimes we need to create a custom panel where the out-of-box panels may not full-fill the need. I came across one such situation where I need to show the items layered over one another.

It’s a Windows Phone 7 Pizza application, where user can choose the toppings, which are shown on top of a Pizza as if its a real one.

I used the following approach to show toppings on a pizza base.

  • Use an Image control to show the base.
  • Place an ItemsControl with images at Z-index as the Image Control.

The following is the xaml code,

Which resulted in the following output,

In ordered to layer the topping images on one another, we need to change the ItemsPanel from StackPanel to a CustomPanel which removes the spacing between the collection items.

Creating the Custom Panel

Create a new class derived from Panel.

    public class CustomPanel : Panel
    {
        public CustomPanel() : base()
        {

        }
    }

All that’s required is to,

  1. Override the MeasureOverride method to influence the size of the child elements.
  2. Override the ArrangeOverride method to influence the position of the child elements in the panel.
The following code shows MeasureOverride,
     protected override Size MeasureOverride(Size availableSize)
        {
            Size availableSpace = new Size(double.PositiveInfinity, double.PositiveInfinity);
            Size desiredSize = new Size(0, 0);

            foreach (UIElement child in this.Children)
            {
                child.Measure(availableSpace);
                desiredSize.Width = Math.Max(desiredSize.Height, child.DesiredSize.Width);
                desiredSize.Height = Math.Max(desiredSize.Height, child.DesiredSize.Height);
            }
            return desiredSize;
        }
The following code shows ArrangeOverride, where all the child items are given a starting point (0, 0), such that every element is positioned at the same place in the panel.
     protected override Size ArrangeOverride(Size finalSize)
        {
            Size returnSize = finalSize;
            //The location where the child will be displayed
            foreach (FrameworkElement child in Children)
            {
                Point location = new Point(0, 0);
                child.Arrange(new Rect(location, child.DesiredSize));

                returnSize.Width = Math.Max(returnSize.Height, child.DesiredSize.Width);
                returnSize.Height = Math.Max(returnSize.Height, child.DesiredSize.Height);
            }
            //Return the total size used
            return returnSize;
        }
Now let’s change the ItemsPanel to our Custom Panel,

And here is the output,

Leave a Reply

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