Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Understanding MeasureOverride and ArrangeOverride

0.00/5 (No votes)
29 Sep 2015 1  
The article will take you through the layout process in WPF.

MeasureOverride and ArrangeOverride

To build an effective and appealing UI in WPF, we should be aware of the layout process which takes places while creating the controls and in turn to understand the layout process, we should be aware of the MeasureOverride() and ArrangeOverride() methods of the FrameworkElement class.

MeasureOverride() and arrangeOverride() are the two methods which take part in the layout process of the WPF element tree. These methods basically use the two other methods provided by the UIElement class which are Measure() and Arrange() methods. To better understand this whole process of layout in WPF, first we need to know the class hierarchy of the controls in WPF.

The below figure should be able to make lots of thing clear about the class level hierarchy of the elements in WPF.

Visual Class Hierarchy in WPF

UIElement class from the above hierarchy contains two methods which are used in the layout process which I will discuss shortly. This class also contains the RenderTransform property which is used to do the transformations.

FrameworkElement class contains all the properties which help us to give the shape to an element. These properties are like Height, Width, All types of alignments and Margin. A FrameworkElement is best suited when you also want to provide custom sizing and positioning of elements, data binding, and styles.

Panel class contains a UIElementCollection property which contains all the elements of that class.

The Layout Process

The layout process is executed when the element is rendered for the first time. The layout system in WPF is a conversation between the layout container and its children.

This conversation is basically a two-step process which we will learn further.

  • Step 1: Measure
  • Step 2: Arrange

Step 1 (Measure): Following are the steps which take place in the measure process.

  • Each element calculates the desired size and determines how big it wants to be.
  • This is achieved by the element by calling the Measure() method on each child and access each child’s desired size property. If the child element has more child elements, in that case the child element also determines all its child’s desired size before returning its own desired size to the parent control.
  • The parent can access the desired size from the previous step and calculate its own desired size.
  • This process walks down the visual tree and starts at the top of level, that means the topmost parent calls the measure() method on each direct child and goes till the end.
  • After this step, each element knows how big it wants to be and thus size is stored in the desired size property of each element.

Step 2 (Arrange): Following are the steps which take place in the arrange process.

  • Each element arranges its child by calling Arrange() method on each direct child.
  • The Arrange() method takes the final size (which we have calculated in Measure Step) and location, i.e., the element knows the position where it has to render and the size which it has to render.

After these two steps, the rendering occurs and element appears on the screen.

Layout Process Working

We can better understand the layout process when we should ourselves be able to create something which utilizes all the steps mentioned earlier.

And to better demonstrate the working of the MeasureOverride() and ArrangeOverride() methods, I have created my own panel which arranges all the controls in a ‘V’ shaped layout as shown in the figure below. Though I am not sure where we should be able to use this kind of panel but to show the demonstration, I have created it.

NOTE: Please note that this panel only works if we have odd number of children(UIElements). I am leaving to reader to implement it for even number of UIElements

Layout process in WPF

To create my own panel which should arrange elements in this particular shape, we should first of all create a custom class derived from Panel class of WPF framework as shown in the below code listing.

Please note that the coordinate system of WPF works as shown below. To understand the below code, we should know this thing.

Co-ordinate system in WPF

Now in the below code listing, you can see that I have implemented the overridden methods MeasureOverride() and ArrangeOverride().

public class DiagnolPanel:Panel
    {
        protected override Size MeasureOverride(Size availableSize)
        {
            var mySize = new Size();

            foreach (UIElement child in this.InternalChildren)
            {
                child.Measure(availableSize);
                mySize.Width += child.DesiredSize.Width;
                mySize.Height += child.DesiredSize.Height;
            }

            return mySize;
        }    

        protected override Size ArrangeOverride(Size finalSize)
        {
            var location = new Point();

            int childNumber = 0;
            int middleChild = GetTheMiddleChild(this.InternalChildren.Count);

            foreach (UIElement child in this.InternalChildren)
            {
               
                if (childNumber < middleChild)
                {
                    child.Arrange(new Rect(location, child.DesiredSize));
                    location.X += child.DesiredSize.Width;
                    location.Y += child.DesiredSize.Height;
                }
                else
                {
                    //The x location will always keep increasing, there is no need to take care of it
                    location.X = GetXLocationAfterMiddleChild(childNumber);

                    //If the UIElements are odd in number
                    if (this.InternalChildren.Count % 2 != 0)
                    { 
                        //We need to get the Y location of the child before middle location, 
                        //to have the same Y location for the child after middle child                      
                        int relativeChildBeforeMiddle = middleChild - (childNumber - middleChild);
                        location.Y = GetYLocationAfterMiddleChild(relativeChildBeforeMiddle);
                    }
                    else
                    {
                       ///TODO: Do the design for the even number of children
                    }

                    child.Arrange(new Rect(location, child.DesiredSize));
                }

                childNumber++;
            }

            return finalSize;
        }

        private double GetXLocationAfterMiddleChild(int childNUmber)
        {
            double xLocation = 0;
            for (int i = 0; i < childNUmber; i++)
            {
                xLocation += this.InternalChildren[i].DesiredSize.Width;
            }

            return xLocation;
        }

        private double GetYLocationAfterMiddleChild(int relativeChildNumber)
        {            
            UIElement correspondingChild = this.InternalChildren[relativeChildNumber - 2];
            Point pointCoordinates = 
            correspondingChild.TransformToAncestor((Visual)this.Parent).Transform(new Point(0, 0));

            return pointCoordinates.Y;
        }

        private int GetTheMiddleChild(int count)
        {
            int middleChild;
            if (count % 2 == 0)
            {
                middleChild = count / 2;
            }
            else
            {
                middleChild = (count / 2) + 1;
            }

            return middleChild;
        }
    }
}

And use this panel class in my XAML to arrange the UIElements as shown below:

<local:DiagnolPanel>
        <Button BorderBrush="Black" Background="Red" Content="0" Width="40"></Button>

Conclusion

If we try to understand the layout process without a proper example, it could be a bit confusing and it can be easily misunderstood.

I hope I have tried to explain the working of the layout process in WPF in a simple and better way. I have attached the sample code here - XAMLLayoutBasic for your reference. Please let me know your thoughts about the article.

The post Understanding MeasureOverride and ArrangeOverride appeared first on Dot Net For All.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here