title: How to implement a WrapPanel with a header and footer
body: <p>I am trying to implement a custom control that acts similarly to a standard WrapPanel, but that allows you to specify a header and footer. Visually, this is what I am trying to accomplish:</p>
  
  <p><a href="https://i.stack.imgur.com/2R6Ze.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/2R6Ze.png" alt="enter image description here"></a></p>
  
  <p>I have created a custom control that seems to leave room for the header and footer items, but I am unable to get them to visually appear. This is my first attempt at any sort of custom control, so any help or input is appreciated!</p>
  
  <p>C#</p>
  
  <pre><code>using System;
  using System.Windows;
  using System.Windows.Controls;
  
  namespace MyProject.Extras
  {
      public class HeaderedFooteredPanel : Panel
      {
          public FrameworkElement Header
          {
              get { return (FrameworkElement) GetValue(HeaderProperty); }
              set { SetValue(HeaderProperty, value); }
          }
          public FrameworkElement Footer
          {
              get { return (FrameworkElement)GetValue(FooterProperty); }
              set { SetValue(FooterProperty, value); }
          }
  
          public static DependencyProperty HeaderProperty = DependencyProperty.Register(
              nameof(Header),
              typeof(FrameworkElement),
              typeof(HeaderedFooteredPanel),
              new PropertyMetadata((object)null));
          public static DependencyProperty FooterProperty = DependencyProperty.Register(
              nameof(Footer),
              typeof(FrameworkElement),
              typeof(HeaderedFooteredPanel),
              new PropertyMetadata((object)null));
  
          protected override Size MeasureOverride(Size constraint)
          {
              double x = 0.0;
              double y = 0.0;
              double largestY = 0.0;
              double largestX = 0.0;
  
              var measure = new Action&lt;FrameworkElement&gt;(element =&gt;
              {
                  element.Measure(constraint);
                  if (x &gt; 0 &amp;&amp;                                                // Not the first item on this row
                      (x + element.DesiredSize.Width &gt; constraint.Width) &amp;&amp;   // We are too wide to fit on this row
                      ((largestY + element.DesiredSize.Height) &lt;= MaxHeight)) // We have enough room for this on the next row
                  {
                      y = largestY;
                      x = element.DesiredSize.Width;
                  }
                  else
                  {
                      /* 1) Always place the first item on a row even if width doesn't allow it
                       *      otherwise:
                       * 2) Keep placing on this row until we reach our width constraint
                       *      otherwise:
                       * 3) Keep placing on this row if the max height is reached */
  
                      x += element.DesiredSize.Width;
                  }
  
                  largestY = Math.Max(largestY, y + element.DesiredSize.Height);
                  largestX = Math.Max(largestX, x);
              });
  
              measure(Header);
  
              foreach (FrameworkElement child in InternalChildren)
              {
                  measure(child);
              }
  
              measure(Footer);
  
              return new Size(largestX, largestY);
          }
  
          protected override Size ArrangeOverride(Size finalSize)
          {
              double x = 0.0;
              double y = 0.0;
              double largestY = 0.0;
              double largestX = 0.0;
  
              var arrange = new Action&lt;FrameworkElement&gt;(element =&gt;
              {
                  if (x &gt; 0 &amp;&amp;                                                // Not the first item on this row
                      (x + element.DesiredSize.Width &gt; finalSize.Width) &amp;&amp;    // We are too wide to fit on this row
                      ((largestY + element.DesiredSize.Height) &lt;= MaxHeight)) // We have enough room for this on the next row
                  {
                      y = largestY;
                      element.Arrange(new Rect(new Point(0.0, y), element.DesiredSize));
                      x = element.DesiredSize.Width;
                  }
                  else
                  {
                      /* 1) Always place the first item on a row even if width doesn't allow it
                       *      otherwise:
                       * 2) Keep placing on this row until we reach our width constraint
                       *      otherwise:
                       * 3) Keep placing on this row if the max height is reached */
  
                      element.Arrange(new Rect(new Point(x, y), element.DesiredSize));
                      x += element.DesiredSize.Width;
                  }
  
                  largestY = Math.Max(largestY, y + element.DesiredSize.Height);
                  largestX = Math.Max(largestX, x);
              });
  
              arrange(Header);
  
              foreach (FrameworkElement child in InternalChildren)
              {
                  arrange(child);
              }
  
              arrange(Footer);
  
              return new Size(largestX, largestY);
          }
      }
  }
  </code></pre>
  
  <p>Usage in XAML:</p>
  
  <pre><code>&lt;ItemsControl ItemsSource="{Binding SomeItems}" ItemTemplate="{StaticResource SomeTemplate}"&gt;
      &lt;ItemsControl.ItemsPanel&gt;
          &lt;ItemsPanelTemplate&gt;
              &lt;extras:HeaderedFooteredPanel&gt;
                  &lt;extras:HeaderedFooteredPanel.Header&gt;
                      &lt;TextBlock Text="Header" /&gt;
                  &lt;/extras:HeaderedFooteredPanel.Header&gt;
                  &lt;extras:HeaderedFooteredPanel.Footer&gt;
                      &lt;TextBlock Text="Footer" /&gt;
                  &lt;/extras:HeaderedFooteredPanel.Footer&gt;
              &lt;/extras:HeaderedFooteredPanel&gt;
          &lt;/ItemsPanelTemplate&gt;
      &lt;/ItemsControl.ItemsPanel&gt;
  &lt;/ItemsControl&gt;
  </code></pre>