Creating a custom panel using WPF

The Grid, StackPanel, WrapPanel and DockPanel are used to layout controls in WPF. All four are derived from the WPF Panel class. So if we want to create our own “custom panel” we obviously use the Panel as our starting point.

So to start with, we need to create a subclass of the Panel class in WPF. We then need to override both the MeasureOverride and ArrangeOverride methods.

public class MyCustomPanel : Panel
{
   protected override Size MeasureOverride(Size availableSize)
   {
      return base.MeasureOverride(availableSize);
   }

   protected override Size ArrangeOverride(Size finalSize)
   {
      return base.ArrangeOverride(finalSize);
   }
}

WPF implements a two pass layout system to both determine the sizes and positions of child elements within the panel.

So the first phase of this process is to measure the child items and find what their desired size is, given the available size.

It’s important to note that we need to call the child elements Measure method before we can interact with it’s DesiredSize property. For example

protected override Size MeasureOverride(Size availableSize)
{
   Size size = new Size(0, 0);

   foreach (UIElement child in Children)
   {
      child.Measure(availableSize);
      resultSize.Width = Math.Max(size.Width, child.DesiredSize.Width);
      resultSize.Height = Math.Max(size.Height, child.DesiredSize.Height);
   }

   size.Width = double.IsPositiveInfinity(availableSize.Width) ?
      size.Width : availableSize.Width;

   size.Height = double.IsPositiveInfinity(availableSize.Height) ? 
      size.Height : availableSize.Height;

   return size;
}

Note: We don’t want to return a infinite value from the available width/height, instead we’ll return 0

The next phase in this process is to handle the arrangement of the children using ArrangeOverride. For example

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

In the above, minimal code, we’re simply getting each child element’s desired size and arranging the child at point 0, 0 and giving the child it’s desired width and height. So nothing exciting there. However we could arrange the children in other, more interesting ways at this point, such as stacking them with an offset like a deck of cards or largest to smallest (or vice versa) or maybe recreate an existing layout but use transformation to animate their arrangement.