Custom Layout in WPF

Posted: March 14, 2010 in .NET, WPF
Tags: ,

The layout system in WPF is responsible for measuring and arranging the user interface elements within the panel and displaying them on screen.This is a two phase process.In the measure phase the panel will measure what is the amount of space required by each of it’s children, in order to find out the total space required.In the next arrange phase it will find out how much space it actually has and accordingly render the elements as per predefined logic.

WPF provides a set of layout panels like WrapPanel, DockPanel,StackPanel,Grid, Canvas etc. out of the box.The base class for all these is the System.Windows.Controls.Panel.One it’s important properties is Children.This property is a collection of System.Windows.Control.UIElement and represents all the child elements contained in the panel.

Panel class is derived from the System.Windows.FrameworkElement class and it has two important virtual methods:

  • protected virtual Size MeasureOverride(Size availableSize) – This method is overridden by the classes implementing a custom panel in order to find out the space required by the elements within the Panel
  • protected virtual Size ArrangeOverride(Size finalSize) – This method is overridden by the classes implementing a custom panel in order to add the logic of arranging the elements within the Panel based on available space.

Here we will develop a custom panel with very simple logic, it will display all it’s UI elements in the shape of a “V”.The code for the custom class is show below:

    public class VLayout : Panel 
    {
        protected override 
            System.Windows.Size MeasureOverride
            (System.Windows.Size availableSize)
        { 

        }
        protected override System.Windows.Size ArrangeOverride
            (System.Windows.Size finalSize)
        { 

        } 

    } 

In the MeasureOverride method we will build a logic to measure the space required to arrange all the UI Elements in a V form.This will be done invoking the Measure method on UIElement objects.The Measure method will accept the available size as input and updates the DesiredSize property of the UI Element objects. This property stores the computed size for that UIElement.

protected override 
    System.Windows.Size MeasureOverride
    (System.Windows.Size availableSize)
{
    Size measuredSize = Size.Empty;
    Size childSize    = Size.Empty; 

    double firstArmHeight = 0;
    double secondArmHeight = 0;
    double totalWidth  = 0;
    int armLength = Children.Count / 2;
    for(int i=0;i<Children.Count;i++)
    {
        Children[i].Measure(new Size
            (double.PositiveInfinity, double.PositiveInfinity)); 

        childSize = Children[i].DesiredSize; 

        totalWidth += childSize.Width;
        //Compute Height For First Arm of V
        if (i + 1 <= armLength)
        {
            firstArmHeight += childSize.Height;
        }
        //Compute Height For Second Arm of V
        else
        {
            secondArmHeight += childSize.Height;
        } 

    }
    measuredSize = new Size(totalWidth, Math.Max(firstArmHeight, secondArmHeight));
    return measuredSize;
} 


In the ArrangeOverride method we will build a logic to arrange all the UI Elements in a V shape.This will be done invoking the Arrange method on UIElement objects.The Arrange method will accept a System.Windows.Rect object based on the values of DesiredSize property of the UI Element objects.

protected override System.Windows.Size ArrangeOverride
      (System.Windows.Size finalSize)
  {
      Point location = new Point();
      Rect childRect = Rect.Empty;
      int armLength = Children.Count / 2;
      for (int i = 0; i < Children.Count; i++)
      {
          childRect = new Rect(location, Children[i].DesiredSize);
          Children[i].Arrange(childRect);
          if (i + 1 < armLength)
          {
              location.Offset(childRect.Width, childRect.Height);
          }
          else if (i + 1 == armLength)
          {
              location.Offset(childRect.Width, 0);
          }
          else
          {
              location.Offset(childRect.Width, -childRect.Height);
          }
      }
      return new Size(Math.Abs(location.X), Math.Abs(location.Y));
  } 

So now our custom layout is ready.

We will use the following code to test this out.

<Window x:Class="CustomLayoutDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:VLP="clr-namespace:CustomLayoutDemo"
    Title="Window1" Height="300" Width="400">
    <VLP:VLayout>
        <TextBox Width="50" Height="20" Text="First"></TextBox>
        <TextBox Width="50" Height="20" Text="Second"></TextBox>
        <TextBox Width="50" Height="20" Text="Third"></TextBox>
        <TextBox Width="50" Height="20" Text="Fourth"></TextBox>
        <TextBox Width="50" Height="20" Text="Fifth"></TextBox>
        <TextBox Width="50" Height="20" Text="Sixth"></TextBox>
        <TextBox Width="50" Height="20" Text="Seventh"></TextBox>
    </VLP:VLayout>
</Window> 

The windows will show up as shown below:

clyt

About these ads
Comments
  1. Custom Layout in WPF « Sankarsan’s Journal…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  2. Custom Layout in WPF « Sankarsan’s Journal…

    Thank you for submitting this cool story – Trackback from PimpThisBlog.com…

  3. Custom Layout in WPF « Sankarsan’s Journal…

    Thank you for submitting this cool story – Trackback from Servefault.com…

  4. Social comments and analytics for this post…

    This post was mentioned on Twitter by outcoldman: Custom Layout in WPF http://tinyurl.com/y8bekuv

  5. [...] Custom Layout in WPF Short article walking through creating custom layouts in WPF. [...]

  6. Nico says:

    I’m getting an error saying that the type was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built.

    Can you help me?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s