zoukankan      html  css  js  c++  java
  • WPF MeasureOverride And ArrangeOverride

    在UIElement布局的时候,我们要知道父窗体或父控件要给子控件分配多少空间,换句话说子控件需要父控件提供多少空间给它。

    这些步骤在什么时候发生呢?

    这些过程来自UIElement的Measure 和Arrange,所以我们来重写这两个方法。看看里面到底做了些什么。

    父MeasureOverride 和ArrangeOverride

    Measure(测量),此方法实现:父元素从其自身的 MeasureCore 实现调用此方法以形成递归布局更新。

    其中Measure方法传入的参数是availableSize,这个availableSize是一个Size类型,表示的是父元素可以提供的大小。

    下面用实例来讲解。

    新建一个PlotPanel类.

       1:  public class PlotPanel:Panel
       2:      {
       3:         protected override Size MeasureOverride(Size availableSize)
       4:         {
       5:             Size size=new Size();
       6:             foreach (UIElement child in InternalChildren)
       7:             {
       8:                 child.Measure(availableSize);
       9:                 size = child.DesiredSize;
      10:             }
      11:             return size;
      12:         }
      13:   
      14:         protected override Size ArrangeOverride(Size finalSize)
      15:         {
      16:             foreach (UIElement child in InternalChildren)
      17:             {
      18:                 double x = 50;
      19:                 double y = 50;
      20:                 child.Arrange(new Rect(new Point(x,y),child.DesiredSize));
      21:             }
      22:             return finalSize;
      23:         }
      24:      }

    这里的PlotPanel类如果有子控件的话,他就会去测量和安排子控件的空间大小。

    假如我们给PlotPanel一个子控件为Button,它想要一个宽度和高度为50的大小。

    PlotPanel先会调用MeasureOverride方法,然后会传给他一个availableSize(可用大小),假如这里的PlotPanel的高度和宽度为400,那么这个availableSize就为(400,400)。

    这里的创建一个size对象( Size size=new Size()),目的是用来返回一个子控件希望的大小(DesiredSize),这时PlotPanel就会foreach子控件,得它DesiredSize这个值。

    根据上面的数据这里的child.DesiredSize应该是(50,50).父控件得到子控件的希望大小后,就要去安排(Arrange)它,也就是在界面上呈现它的大小。

    这时PlotPanel就会去调用ArrangeOverride方法。传入的参数是finalSize(finalRect为Parent最后给你的大小),这里有人会说,子控件已经返回一个希望的大小,为什么还要一个finalSize呢?这里我的理解是,父容器虽然知道了你想要的大小,但你想要的DesiredSize比我给你的availableSize小的话,我还是会给你availableSize大小,也就是这里的 finalSize大小为availableSize,反之给DesiredSize.

    根据上面所说这里我们的finalSize为(400,400)。然后执行child.Arrange();画一个矩形;他的宽和高为(50,50),但还是返回了一个finalSize(400,400).这里真正要看的是child的RenderSize(child实际的大小)。这里的child.RenderSize为(50,50).

    在xaml中。

    <Window x:Class="MeasureAndArrange.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:my="clr-namespace:MeasureAndArrange"
            Title="MainWindow" Height="400" Width="400">
            <my:PlotPanel>
                <Button Width="50" Height="50"/>
            </my:PlotPanel>
    </Window>

    我们运行看看:
    image

    假如,PlotPanel给这个Button一个(30,30)的大小,那会怎么样呢?

    我们修改下代码:

       1:  protected override Size MeasureOverride(Size availableSize)
       2:         {
       3:             foreach (UIElement child in InternalChildren)
       4:             {
       5:                 child.Measure(new Size(30,30));
       6:             }
       7:             return availableSize;
       8:         }

    运行过程:

    availableSize=(400,400)

    finalSize=(400,400)

    child.DesiredSize=(50,50)

    child.RenderSize=(30,30)

    效果图:

    image

    很明显,Button被clip了.

    父和子的MeasureOverride 和ArrangeOverride

    我们先新建两个类MyPanelParent和MyPanel。

    先看代码:

    父类

       1:  public class MyPanelParent:Panel
       2:      {
       3:         protected override Size MeasureOverride(Size availableSize)
       4:         {
       5:             foreach (UIElement child in InternalChildren)
       6:             {
       7:                 child.Measure(new Size(120,120));
       8:             }
       9:             return availableSize;
      10:         }
      11:   
      12:         protected override Size ArrangeOverride(Size finalSize)
      13:         {
      14:             double x = 0;
      15:             foreach (UIElement child in InternalChildren)
      16:             {
      17:                 child.Arrange(new Rect(x,0,100,100));
      18:                 x += 100;
      19:             }
      20:             return finalSize;
      21:         }
      22:      }

    子类

       1:   public class MyPanel:Panel
       2:     {
       3:         protected override Size MeasureOverride(Size availableSize)
       4:         {
       5:             foreach (UIElement child in InternalChildren)
       6:             {
       7:                 child.Measure(availableSize);
       8:             }
       9:             return new Size(50,50);
      10:         }
      11:   
      12:         protected override Size ArrangeOverride(Size finalSize)
      13:         {
      14:             double x = 0;
      15:             foreach (UIElement child in InternalChildren)
      16:             {
      17:                child.Arrange(new Rect(new Point(x,0),child.DesiredSize));
      18:                 x += child.DesiredSize.Width;
      19:             }
      20:             return new Size(80,80);
      21:         }
      22:     }

    xaml中

       1:  <Window x:Class="MeasureAndArrange.MainWindow"
       2:          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       3:          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       4:          xmlns:my="clr-namespace:MeasureAndArrange"
       5:          Title="MainWindow" Height="600" Width="600">
       6:      <Grid>
       7:          <Canvas>
       8:              <my:MyPanelParent Height="400" Width="400" Background="Linen" Canvas.Left="10" Canvas.Top="10">
       9:                  <my:MyPanel  Background="Red" />
      10:                  <my:MyPanel  Background="Red" />
      11:              </my:MyPanelParent>
      12:          </Canvas>
      13:      </Grid>
      14:  </Window>

    这里的大概流程是首先MyPanelParent执行MeasureOverride方法,当执行到 child.Measure时,就会去调用MyPanel的MeasureOverride方法。

    通过递归一个一个实现测量。

    然后MyPanelParent执行ArrangeOverride方法,同样执行到child.Arrange时,调用MyPanel的ArrangeOverride方法。

    下面分析下运行过程:

    Measure

    首先MyPanelParent的MeasureOverride方法传进来一个availableSize大小为(400,400),因为我们在xaml中设置了这个可用大小。

    然后测量给MyPanel一个大小为(120,120),从这里可以看出child.Measure(new Size(120,120));于是调用MyPanel的MeasureOverride(Size availableSize)

    availableSize为(120,120).而MyPanel返回了一个DesireSize为(50,50)给MyPanelParent。

    Arrange

    MyPanelParent这时传进了一个finalSize(400,400),这个大小也就是MyPanelParent的availableSize,然后给MyPanel安排一个矩形宽高为(100,100)。

    这时调用MyPanel的ArrangeOverride传入的finalSize(100,100),这个finalSize就是MyPanelParent对child安排的(Arrange)大小。而这里MyPanel它说,

    它只要呈现(80,80)的Size。这个大小在MyPanelParent给他的finalSize大小之内,所以最后的RenderSize为(80,80).

    图:

    imageimage

    image

    这里主要参考MSDN和其他人的blogs.

  • 相关阅读:
    Palindrome Partitioning
    triangle
    Populating Next Right Pointers in Each Node(I and II)
    分苹果(网易)
    Flatten Binary Tree to Linked List
    Construct Binary Tree from Inorder and Postorder Traversal(根据中序遍历和后序遍历构建二叉树)
    iOS系统navigationBar背景色,文字颜色处理
    登录,注销
    ios 文字上下滚动效果Demo
    经常崩溃就是数组字典引起的
  • 原文地址:https://www.cnblogs.com/dingli/p/2024786.html
Copyright © 2011-2022 走看看