WPF/Silverlight Layout System Overview-Measure

Source: Internet
Author: User
Preface

In WPF/Silverlight, if an existing Element cannot meet your special needs and you may want to customize the Element, you may be faced with rewriting the MeasureOverride and ArrangeOverride methods, the two methods are provided by the Layout System of WPF/SL for user-defined interfaces. Therefore, it is necessary to understand the working mechanism of the Layout system and customize the Element. So how does the WPF/SL Layout system work? Next, let me briefly describe it and then analyze it in the following chapters.

In short, the Layout system of WPF is a recursive system. It has two sub-processes, which always start by calling the Measure method of the parent element and end by calling the Ararnge method, after entering each sub-process, the parent element will call the Measure of the child element, and then call the Arrange method of the child element to continue recursion. One call to two sub-processes can be considered as one session, which can be understood as follows:

 

This session can be described in the following section:

Sub-process 1: the parent gives the child an availableSize according to his own policy and initiates a dialogue. by calling the child's Measure (availableSize) method, the parent asks the child: how much space do you want to display yourself? After receiving the inquiry, the child asks for the size of availableSize given by the parent and some restrictions, such as Margin, Width, and so on. The Child replies: I want a space of XXX. After the parent obtains the expected size of space given by the child, the child is allocated space according to his/her policy, and then enters the second sub-process.

Sub-process 2: After the parent obtains the expected space of the child, he decides to allocate the child a rectangle with the finalRect size based on his own situation. Then he initiates a dialogue and calls the child's Arrange (finalRect) I gave you a space like finalRect. After the child obtains the size, he will deploy the content of the content, and after the layout is complete, he will tell the parent: Actually, I used a space of XXX to draw my own content. After the parent knows it, he does not say anything. He still places the child according to the finalRect assigned to him. If the final area drawn by the child is greater than this area, the child is cropped by the parent. The Layout process is completed.

Through the above two sub-processes, I have more or less a preliminary understanding of the WPF Layout system. In the next chapter, I will describe the specific actions of the Measure Process and the Arrange process, it helps you understand the Layout System in depth.

 

 

Preset conditions  

In the following preset scenario, we will explain the Layout system.

Suppose: We need to customize a Panel. The type is * MyPanel *. The parent of MyPanel is * MyPanelParent *, which is also a Panel. The child of MyPanel is * MyPanelChild *, which is also a Panel.

Entry 1: rewrite the MeasureOverride () and ArrangeOverride () of MyPanelParent to study how the parent influences the Layout of MyPanel;

Entry Point 2: rewrite the MyPanel. MeasureOverride () and ArrangeOverride methods to study the attributes that affect the Layout of MyPanel and the points that should be paid attention to when rewriting these two methods;

Note: In the following research, I only set the horizontal direction based on the Width of the Element, that is, the dimension of the horizontal direction. All the data is set only in the horizontal direction, and the vertical direction is set consistent with the horizontal direction, but it is not described.

 

Measure Process Overview   1. Measure Impact of the process

See the following settings:

<Window x:Class="WpfApplication1.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        Title="MainWindow" Height="522" Width="594" Loaded="Window_Loaded" xmlns:my="clr-namespace:WpfApplication1">    <Canvas>        <my:MyPanelParent x:Name="myPanelParent1" Height="400" Width="400" Background="Green" Canvas.Left="10" Canvas.Top="10">            <my:MyPanel Margin="10" x:Name="myPanel1" Background="Red" MinWidth="150" Width="200"  MaxWidth="250"/>            <my:MyPanel Margin="10" x:Name="myPanel2" Background="Red" MinWidth="150" Width="200" MaxWidth="250"/>        </my:MyPanelParent>    </Canvas></Window>
Public class MyPanelParent: Panel {protected override System. windows. size MeasureOverride (System. windows. size availableSize) {foreach (UIElement item in this. internalChildren) {item. measure (new Size (120,120); // here is the entry} return availableSize;} protected override System. windows. size ArrangeOverride (System. windows. size finalSize) {double x = 0; foreach (UIElement item in this. internalChildren) {item. arrange (new Rect (x, 0, item. desiredSize. width, item. desiredSize. height); x + = item. desiredSize. width;} return finalSize;} public class MyPanel: Panel {protected override System. windows. size MeasureOverride (System. windows. size availableSize) {foreach (UIElement item in this. internalChildren) {item. measure (availableSize);} return new Size (50, 50); // MyPanel returns the expected Size} protected override System. windows. size ArrangeOverride (System. windows. size finalSize) {double xCordinate = 0; foreach (UIElement item in this. internalChildren) {item. arrange (new Rect (new Point (xCordinate, 0), item. desiredSize); xCordinate + = item. desiredSize. width ;}return finalSize ;}}

 

 

After the preceding settings, after the application is running, the Window is displayed as follows:

Analyze the settings:

MyPanel1.Width = 200, MyPanel1.MinWidth = 150, MyPanel1.MaxWidth = 250, MyPanel1.Margin = Thickness (10)

The input parameter MyPanel1.Measure () is 120*120, and MyPanel1.MeasureOverride returns 50*50

Analysis result:

The actual size (red part) of MyPanel1 is 100*50.

The result shows that the red part is affected by multiple factors. Someone may ask, I have set MyPanel. width = 200, but how to draw the Width is 100; MyPanel. the Height is not set, but the value is 50. Why is it not another value. Next, I will explain how the result is obtained through the Measure flowchart:

After reading this, some people may see some clues, or they may not be very clear. I will summarize what the Measure process really wants based on my own understanding?

1. the first point is very clear. MyPanelParent calls MyPanel. the Measure process is to get MyPanel. desiredSize and MyPanelParent determine the size of the MyPanel to be placed by referring to the DesiredSize of the child in Arrange.

2. MyPanel. DesiredSize is the size and space that contains Margin and content.

3. myPanel. the constrainedSize parameter passed in MeasureOverride is the size of the base class implementation to split Margin, and then calculate the value of a MyPanel Based on the settings of MyPanel for MinWidth, MaxWidth, and Width, during customization, you do not need to care about your own Margin in MeasureOverride, and other base classes that affect Layout attributes. You only need to arrange your own content areas in the scope class of the given parameter; MyPanel. minWidth, Width, and MaxWidth are all set for the content area, excluding the Margin section.

4. if the Width is not set, an expected content area size can be returned when MeasureOverride returns. It will be adjusted by MinWidth and MaxWidth. After the adjustment, it still needs to be measured by MyPanelParent (Narration: don't be confused, don't play with the Layout system, and set MinWidth and MaxWidth to stay in this range .)

5. no matter how MyPanel sets its own Width, MinWidth, MaxWidth, and returns a size in MeasureOverride, this shows how much space you want to display your content. However, this is only what you expect, the expectation is beautiful, and the reality is cruel. It must be limited to MyPanel. availableSize refers to the parameter availableSize passed in at the beginning of Measure to partition MyPanel. if the range after Margin is smaller than this range, it is satisfied. If it is greater than this range, it is cut. (Poor, always subject to the parent)

6. Parameters and attributes that affect the Measure process have a priority, which is roughly as follows:

Measure method parameter availableSize> MinWidth, Width, MaxWidth> MeasureOverride Return Value

 

2. Transform For Measure Impact of the process

Through the above process, we have probably understood how the Measure process works and how each attribute affects it. However, there is another property we didn't mention, but it also has a great impact on the Measure process. This is LayoutTransform. The following two sections show the specific performance of this attribute.

Set 1:

 

<Window x:Class="WpfApplication1.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        Title="MainWindow" Height="522" Width="594" Loaded="Window_Loaded" xmlns:my="clr-namespace:WpfApplication1">    <Canvas>        <my:MyPanelParent x:Name="myPanelParent1" Height="400" Width="400" Background="Lime" Canvas.Left="10" Canvas.Top="10">            <my:MyPanel Margin="10" x:Name="myPanel1" Background="Red" Width="200">                <my:MyPanel.LayoutTransform>                    <RotateTransform Angle="90"/>                </my:MyPanel.LayoutTransform>            </my:MyPanel>            <my:MyPanel Margin="10" x:Name="myPanel2" Background="Red" MinWidth="150" MaxWidth="250"/>        </my:MyPanelParent>    </Canvas></Window>

 

    public class MyPanelParent:Panel    {        protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize)        {            foreach (UIElement item in this.InternalChildren)            {                item.Measure(new Size(1000, 800));            }            return availableSize;        }        protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)        {            double x = 0;            foreach (UIElement item in this.InternalChildren)            {                item.Arrange(new Rect(x, 0, item.DesiredSize.Width, item.DesiredSize.Height));                x += item.DesiredSize.Width;            }            return finalSize;        }

 

 
    public class MyPanel : Panel    {        protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize)        {            foreach (UIElement item in this.InternalChildren)            {                item.Measure(availableSize);            }            return new Size(80, 50);        }        protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)        {            double xCordinate = 0;            foreach (UIElement item in this.InternalChildren)            {                item.Arrange(new Rect(new Point(xCordinate, 0), item.DesiredSize));                xCordinate += item.DesiredSize.Width;            }            return finalSize;        }    }

The operation is as follows:

 

Analyze the settings:

MyPanel1.LayoutTransform = new RotateTransform (90) // Rotate 90 degrees

MyPanel1.Width = 200

MyPanel1.Margin = Thickness (10)

The input parameter MyPanel1.Measure () is 1000*800, and MyPanel1.MeasureOverride returns 80*50.

Analysis result:

The actual size of MyPanel1 is 50 × 200, which is obviously rotated 90 degrees.

When running, you will find that the final MyPanel1.DesiredSize is 70 × 220 after the Measure process. That is to say, it is the size after the Transform, and it is obviously rotated. In addition, observe MyPanel. the input parameter of MeasureOverride is 200 × 980. According to the analysis of the Measure Process in the previous section, the width of the input parameter of MeasureOverride is 200, which is predictable because we set MyPanel1.Width to 200, but the Height is 980, which is obviously MyPanel. measure's incoming width is 1000 minus 2*10 and equal to 980. It seems that before going to MeasureOverride, the Layout system also handles the impact of LayoutTransform on the Measure process. It wants MeasureOverride not to care about its own LayoutTransform impact. After MeasureOverride ends, the returned value is 80 × 50. According to the analysis of the Measure Process in the previous section, the width of 80 is adjusted to conform to your own settings, which is 200. Because the height is not set, this 50 will definitely be retained, so the last DesiredSize before Transform should be 220 × 70. However, the base class will Transform the size returned by MeasureOverride to reach the final DesiredSize, so that appropriate space can be allocated to the Arrange to accommodate the size of the MyPanel.

If you set MyPanel1.LayoutTransform in the preceding example to ScaleTransform:

 

<Window x:Class="WpfApplication1.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        Title="MainWindow" Height="522" Width="594" Loaded="Window_Loaded" xmlns:my="clr-namespace:WpfApplication1">    <Canvas>        <my:MyPanelParent x:Name="myPanelParent1" Height="400" Width="400" Background="Lime" Canvas.Left="10" Canvas.Top="10">            <my:MyPanel Margin="10" x:Name="myPanel1" Background="Red" Width="200">                <my:MyPanel.LayoutTransform>                    <ScaleTransform ScaleX="2" ScaleY="2"/>                </my:MyPanel.LayoutTransform>            </my:MyPanel>            <my:MyPanel Margin="10" x:Name="myPanel2" Background="Red" MinWidth="150" MaxWidth="250"/>        </my:MyPanelParent>    </Canvas></Window>

Then observe myPanel. the input parameter of MeasureOverride is 200 × 390. First, 200 is predictable. Because the Width attribute is set, what is the difference between 390 and, in fact, we get 1000 for the 800x800 high 780 introduced by Measure minus the Margin value of 20, and then get 390 after the height is reduced by 2 times according to LayoutTransform, therefore, the input parameter is 200 × 390. As you can see, before the Layout system enters the MeasureOverride, he hopes that the MeasureOverride only cares about how to arrange the content, you do not need to worry about the impact of setting the base class attribute on MeasureOverride. Because the returned value of MeasureOverride is still 80 × 50, it can be inferred that 80 is adjusted to 200, 50 is retained, and the value before Transform is × 50. Because the base class still needs to perform Transform, the actual size of the content area should be 400 × 100. With the addition of Margin, the final DesiredSize must be 420*120, you can try to debug the given code.

 

3. Measure Summary of the process

Summary of the Measure Process

Through the above process analysis, I believe that you have a better understanding of the Measure Process of the WPF Layout system. In fact, there are still some factors that affect the Measure process, such as the UseLayoutRounding attribute, before and after entering the MeasureOverride, the base class is Rounding the parameter according to DPI. This process is fine and you do not need to care about it in your own MeasureOverride. We will summarize which attributes and parameters will affect the Measure process: availableSize passed in MyPanel. Measure, MinWidth, Width, MaxWidth, Margin, UseLayoutRounding, LayoutTransform, and MeasureOverride return values of MyPanel.

 

Measure Process FAQs  

Q1:What isLayout Slot?When can I get it? Where can I get it? 

Layout Slot is the finalRect parameter passed in when the Arrange method is called. This is the rectangle space allocated by the parent to the child to hold the Margin and the content area;

After the Arrange process is complete, you can get it;

You can obtain this information by calling the static class LayoutInformation. GetLayoutSlot (FrameworkElement element.

Q2:What isLayout Clip? When can I get it? Where can I get it? 

Layout Clip is only the size of the content area to be drawn, which is greater than the size of the Margin area after LayoutSlot planing. At this time, the content area is Clip, and the excess part is Clip, the remaining printable part is Layout Clip, which is a Geometry.

After the Arrange process is complete, you can get it;

You can obtain this information by calling the static class LayoutInformation. GetLayoutClip (FrameworkElement element. If the content area can be fully displayed

LayoutClip is Null in the area where the Layout Slot is located to Margin.

Q3:In the parentMeasureOverrideTheMeasureAre there any restrictions on the input parameters? 

Yes. Make sure that availableSize. Width and Height are not NaN; but they can be Infinity.

Q4:Before entering your ownMeasureOverrideWhat should I do with parameters? 

First, you should understand that the input parameter is already the value after the base class planing its own Margin, and considering that the base class affects the attribute of the Measure process.

Second, check whether you have customized Layout attributes, and call the child's Measure method based on your content requirements or your children's situation, and specify the size of the space you want your child to have.

Finally, a desired Size is returned.

Note the following points:

1. when you call a child's Measure method, the input parameter is the maximum space you specify for the child to display the child's Margin and content area, regardless of the desired size, will be cropped by the availableSize you gave him.

2. return an expected value based on its own policy. The expected value should be within the range limited by MinWidth, Width, and MaxWidth. If not, the base class will be adjusted forcibly.

3. The adjusted value of the base class will be adjusted again by the availableSize passed in by the parent class. The returned value cannot be greater than the value after the parameter passed in by the parent class minus the value after Margin.

Q5: MeasureOverrideAre there any restrictions on the returned values? 

Yes. Besides Q5, the returned value will be adjusted again. You must ensure that the returned value of your defined MeasureOverride is a fixed value, not NaN or Infinity. If the value is less than 0, the base class is adjusted to 0.

Q6: DesiredSizeWhat is it? 

DesiredSize is a size determined after the Measure process ends. It is the size that the child expects the parent to allocate to him during Arrange, including the child's Margin region and content region. If the parent needs to call the child's Arrange method during ArrangeOverride, the child's Arrange method should be called to pass in the child's DesiredSize Rect.

Q7:Children'sDesiredSizeAre you sure you want to get such a large space? 

Not necessarily. As mentioned in the Q7 answer, based on the parent policy, if the parent expects to allocate the desired size to the child, the DesiredSize Rect will be passed in when the child's Arrange method is called, for example, for Canvas, the size of the Canvas child is as large as the size of the child's DesiredSize. if the parent is determined based on its own settings, it will not refer to the child's DesiredSize, the input is of course the space that can only be allocated to the child. For example, UniformGrid divides the space equally based on the available size and number of columns, and then allocates the allocated space to each child, not the child's DesiredSize. Allocate space to the child. This process is in the Arrange stage.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.